Can I define my own template functions?

General help with the eC language.
samsam598
Posts: 212
Joined: Thu Apr 14, 2011 9:44 pm

Can I define my own template functions?

Post by samsam598 »

Greetings!

As subjected,if yes,any special concerns should I pay attention to?

Thanks and best regards,
Sam
jerome
Site Admin
Posts: 608
Joined: Sat Jan 16, 2010 11:16 pm

Re: Can I define my own template functions?

Post by jerome »

Hi Sam,

At the moment, eC only have support for class generics.

It is (to some extent) still an experimental feature, and mainly meant to power the type-aware containers (e.g. Array, List, AVLTree, Map...) and Iterator, which provide equivalent functionality to many of the C++ STL classes.

Please read the Templates section in this original blog post for the new feature:

http://www.ecere.com/blog/2008/09/03/ec ... hlighting/

There are 3 types of parameterization possible for classes, being:

- A generic type
- A generic identifier, meant to be a member of a class
- A generic value

You can find examples for the first one (generic type) in all of the ecere source tree's containers (sdk/ecere/src/com/containers). Be aware that it is still experimental and may suffer from some limitations.

The latter 2 are used for the LinkList class (also in that folder).
The LinkList class is a generic link list linking nodes which contain within themselves both a previous and next link member. It uses the generic identifier to define an arbitrary member of the class to serve as the previous and next links. The generic value is used to specialize the link list as either circular or not. These features are only used in the LinkList, and are thus particularly experimental/limited.

As a quick overview, here's some things you can do with a generic class:

Code: Select all

class MyClass<class T>
{
   T what;
   void DoStuff(T something)
   {
      what = something;
      PrintLn(something);
   }
}
 
void Test()
{
   MyClass<int> a { };
   a.DoStuff(30);
}
Again be warned: if you use these features, you may come across limitations (e.g. using it in certain way might crash). There are often ways to work around it, but still if you do, please take the time to report an issue on Mantis so that we can improve the support for these generics! :) If there is something in particular which you would like to do but cannot work around, please let me know and I will try to suggest a work around and/or prioritize a fix in the compiler.

Best regards,

Jerome
samsam598
Posts: 212
Joined: Thu Apr 14, 2011 9:44 pm

Re: Can I define my own template functions?

Post by samsam598 »

As an exercise,I've tried to implement a generic data structure Stack.First I wrote a plain version for int,given below code:

Code: Select all

 
import "ecere"
#include <assert.h>
#include <stdlib.h>
#include <math.h>
 
#define maxStack 16 
class Stack
{
   private:
   int arr[maxStack];
   int top;
   public:
   void push(int elem)
   {
      assert(!isFull());
      arr[top]=elem; 
      ++top;
   }
   int pop()
   {
      assert(!isEmpty()) ;
      --top;
      return arr[top];
 
   }
 
   Stack()
   {
 
      top=0;
 
   }
   bool isFull()
   {
      return top==maxStack;
   }
   bool isEmpty()
   {
      return top==0;
   }
};
 
class App:Application
{
   void Main()
   { 
 
      Stack vec{};
      while(!vec.isFull())
         vec.push(rand());
 
      printf("top()=%d\n",vec.top);
 
      while(!vec.isEmpty())
      {
 
          printf("pop first=%d\n",vec.pop()); 
      }
 
      system("pause");
   }
}
 
The running result was as expected.Except there is a surprise worth to question:
the private field top should not be accessed outside,am I right?But in the Main() calling vec.top is fine,why?

Now I am trying to implement the generic version as below:

Code: Select all

 
import "ecere"
#include <assert.h>
 
 
#define maxStack 16 
class Stack <class T>
{
   private:
   T arr[maxStack];
   int top;
   public:
   void push(T elem)
   {
      assert(!isFull());
      arr[top]=elem; 
      ++top;
   }
   T pop()
   {
      assert(!isEmpty()) ;
      --top;
      return arr[top];
 
   }
 
   Stack()
   {
 
      top=0;
 
   }
   bool isFull()
   {
      return top==maxStack;
   }
   bool isEmpty()
   {
      return top==0;
   }
};
 
class App:Application
{
   void Main()
   { 
 
      Stack<int> vec{};
      vec.push(1);
      vec.push(2);
      vec.push(3);
 
 
      printf("top()=%d\n",vec.top);
 
      while(!vec.isEmpty())
      {
 
          printf("pop first=%d\n",vec.pop()); 
      }
 
      system("pause");
   }
}                          
 
This time the running result is not correct;and if I change Stack<int> to Stack<double>,the output will be correct.This is quite wierd.

Regards,
Sam
jerome
Site Admin
Posts: 608
Joined: Sat Jan 16, 2010 11:16 pm

Re: Can I define my own template functions?

Post by jerome »

Hi Sam,

As I mentioned earlier, these templates are still somewhat shaky grounds.

I've found that if you modify your pop function to return like this:

Code: Select all

return ((T*)arr)[top];
The problem goes away (Works fine for both int and double -- as long as you use %f for double of course). If you wish you could file a Mantis issue for this.
Also be warned that T arr[maxStack] gets compiled to a fixed-sized (as if T took 8 bytes).

On another note, all the predefined container classes inherit from Container, so you could make your Stack class inherit from it as well to test those features. Or it could inherit from Array :)

Regarding top being accessible from App::Main(), please read the chapter on Encapsulation and access control in eC, starting on page 85 in the Tao. It differs significantly from the C++ ideas:
- static means accessible only within the current .ec source file
- private means accessible only within this shared library (.dll/.so)
- public means accessible by all

In no case will a member of any class defined within a .ec file not be accessible within the same .ec file -- I would find this a terrible annoyance. The idea is that classes should be organized in source files according to functionality, e.g. the implementation for a major class and other related classes could go together in one source file, thus making member access between them easy (In C++ terms, you could think of it as all classes within a source files being friends). Things that should not be accessible by other unrelated classes can be made static (though there are currently limitations to the usage of static), and things that should only be invisible to the outside world would be made private (and only be seen within the shared library module source files).

Regards,

Jerome
samsam598
Posts: 212
Joined: Thu Apr 14, 2011 9:44 pm

Re: Can I define my own template functions?

Post by samsam598 »

Hi Jerome,

Thanks a lot.For the private scope,noted.

For the generic Stack function,double and int are fine after tested.But not for char* (String):

Code: Select all

 
   ...
      Stack<String> strVec{};
      String str;
      int i;
 
      for(i=0;i<10;i++)
      {
 
         sprintf(str,"This is the %d line",i);
         strVec.push(str);
      }
 
       while(!strVec.isEmpty())
       printf("pop strVec==>%s\n",strVec.pop());     
 
Output:

This is the 9 line
This is the 9 line
This is the 9 line
...

Don't know whether I missed something very obvious.

Regards,
Sam
jerome
Site Admin
Posts: 608
Joined: Sat Jan 16, 2010 11:16 pm

Re: Can I define my own template functions?

Post by jerome »

Hi Sam,

You missed 2 things here :)

First, the 'String' class at the moment works pretty much like a typedef to 'char *' (so It's essentially a C string)

This means that you need to think of it as such, and so here you're doing a sprintf into an uninitialized pointer.

Additionally, when you push a String onto your class, no special code generates a copy for each added string, so you're essentially pushing the same string (And modifying it will modify all other strings in the stack, since they're the same -- that's why you get the same line printed 10 times).

The following will work:

Code: Select all

      Stack<String> strVec{};
      int i;
 
      for(i=0;i<10;i++)
      {
         strVec.push(PrintString("This is the ", i, " line"));
      }
 
      while(!strVec.isEmpty())
      {
         String s = (String)strVec.pop();
         printf("pop strVec==>%s\n",s);
         delete s;
      }
PrintString works just like Print() (There's also PrintLnString()), but instead of outputting to stdout, it allocates and returns the resulting string.

Regards,

Jerome
samsam598
Posts: 212
Joined: Thu Apr 14, 2011 9:44 pm

Re: Can I define my own template functions?

Post by samsam598 »

Thanks a lot.Got the point(maybe not yet ^_^)

Code: Select all

 
for(i=0;i<10;i++)
      {
 
         char result[255];
         sprintf(result,"This is line %d",i);
         strVec.push(result); 
      } 
 
As a practice I want to make it by pure char array instead of PrintString(),but still it prints This is line 9 ten times.Even if I use another char str[255] and then do strcpy from result to str ,it still does not work.Why?

Regards,
Sam
jerome
Site Admin
Posts: 608
Joined: Sat Jan 16, 2010 11:16 pm

Re: Can I define my own template functions?

Post by jerome »

Hi Sam,

You still need to have one allocated string per thing added to the stack...
This would work:

Code: Select all

for(i=0;i<10;i++)
{
   char result[255];
   sprintf(result,"This is line %d",i);
   strVec.push(CopyString(result)); 
}
-Jerome
jerome
Site Admin
Posts: 608
Joined: Sat Jan 16, 2010 11:16 pm

Re: Can I define my own template functions?

Post by jerome »

You have to realize the life of a char array is limited to its scope (the compound { } brackets around it), so as soon as you're outside of the for loop iteration, it's gone.
samsam598
Posts: 212
Joined: Thu Apr 14, 2011 9:44 pm

Re: Can I define my own template functions?

Post by samsam598 »

Appreciated.
Btw,does CopyString do the same as strdup?

The more I study deep into eC,the more I love.Keeping its features within a deeply thoughtful range other than bloated as c++ makes eC more beautiful and powerful.
Post Reply