slang-users mailing list

[2006 Date Index] [2006 Thread Index] [Other years]
[Thread Prev] [Thread Next]      [Date Prev] [Date Next]

[slang-users] SLang with objects ?


Are there any plans to add support for objects to SLang?

A while ago I was building a library for text forms in
jed and I implemented it in an OO fashion (structures with members
and methods).

The thing that I am missing the most is a way to add new members
to an existing structure. This way I could add some polymorphism.
I found a way to do it (with an empty extra field in the base "class")
but I don't consider this to be a solution:

    typedef struct
    {
       a, b,           % members
       dothis, dothat  % methods
       extra           % derived types can add members
    } Base_Type;

    private define impl_do_this(self) { print(self.a); ... }
    private define impl_do_that(self) { print(self.b); ... }

    % constructor for Base_Type
    define New_Base_Type()
    {
       variable obj = @Base_Type;
       obj.a = 0; obj.b = 0;
       obj.dothis = &impl_do_this;
       obj.dothat = &impl_do_that;
       obj.extra = NULL;
       return obj;
    }

    typedef struct
    {
       c, d,           % extra members for derived type
       op1, op2        % methods
    } Struct_with_extra_members;

    % constructor for Derived_Type
    define New_Derived_Type()
    {
       variable obj = @Base_Type;
       obj.extra = @Struct_with_extra_members;
       obj.extra.c = 0;
       ...
       return obj;
    }

Here I can implement 1 level of derived objects. This was enough
(and not too hard to manage) for the project.
If I wanted to inherit from a derived object I would get obj.extra.extra.
A mess.


Some ideas
==========

The typedef struct construct could be extended like this

    typedef struct {
       c, d,
       op1, op2
    } Derived_Type (Base_Type)

which would produce a structure like

    struct { a, b, dothis, dothat, c, d, op1, op2 }

Another not so elegant solution is something like:

    define New_Derived_Type()
    {
       variable obj = @Base_Type;
       struct_add_member(obj, "c");
       struct_add_member(obj, "d");
       ...
       return obj;
    }

But maybe the best syntax would be to add a keyword like "class" or
"object":

    class Derived_Type (Base_Type)
    {
       c, d, ...
    };

For the classes to be real classes, there should be support
for virtual functions. At the moment it is possible to override
an existing function from the base class:

    private define impl_special_do_this(self)
    { print("Derived " + self.a); ... }

    define New_Derived_Type()
    {
       variable obj = @Base_Type;

       % override a method from the base class
       obj.dothis = &impl_special_do_this;
    }

You can still call the original method from the base class:

    private define impl_special_do_this(self)
    {
       print("Derived implementation calling Base implementation");
       impl_do_this(self);
    }

You have to know which is the base class and what function you
reimplemented in the derived class. You also have to have access
to the function impl_do_this.

To make the code more OO I made all impl_* functions private to
force the programmer to access them only by using object methods.
Now, when I define the derived object in anoter file I no longer
have access to impl_do_this. What I could do is:

    define New_Derived_Type()
    {
       variable obj = @Base_Type;
       ...
       struct_add_member(obj, "base_do_this");
       ...
       % override a method from the base class
       obj.base_do_this = obj.dothis;
       obj.dothis = &impl_special_do_this;
    }

    private define impl_special_do_this(self)
    {
       print("Derived implementation calling Base implementation");
       self.base_do_this();
    }

This could be implemented in SLang library internally. Methods
could somehow be declared virtual. Each instance of an object
would have a poiner to its static type-descriptor (Base_Type).
(could typeof() be used?).
Type-descriptors would have a pointer (__base) to their base
type-descriptors.


    define New_Base_Type()
    {
       variable obj = @Base_Type;
       % Base_Type.__base = NULL

       struct_virtual(obj.dothis, &impl_do_this);
       % converted internally to: typeof(obj).dothis = &impl_do_this
    }
    % Base_Type.dothis points to impl_do_this


    define New_Derived_Type()
    {
       variable obj = @Derived_Type;

       % Derived_Type.__base points to Base_Type
       % Derived_Type.dothis points to impl_do_this

       struct_override(obj.dothis, &impl_special_do_this);
       % converted internally to:
       %   typeof(obj).dothis = &impl_special_do_this
    }
    % Derived_Type.dothis points to impl_special_do_this

A call like obj.dothis() would be converted internally to

    typeof(obj).dothis(obj);

In the above case it would call impl_special_do_this(obj).

A call to a base classes method could be made with a type cast:

    Base_Type(obj).dothis();

This call could perform a check if obj is derived from Base_Type
(using the __base field) and then call

    Base_Type.dothis(obj);

Constructors (and destructors) could be added to classes. They
could be declared for example using a standard name (like with
python):

   create();    % or __init__
   destroy();   % or __del__

How could it all look in SLang:

    class Base
    {
       a = 0, b = 0,
       create = &impl_base_create,
       virtual dothis = &impl_do_this,
       dothat = &impl_do_that
    };
    class Derived (Base)
    {
       c = 0, d = 0,
       create = &impl_derived_create,
       override dothis = &impl_special_do_this,
    };

    x = new Base();     % also calls x.create()
    y = new Derived();
    x.dothis();
    y.dothis();
    Base(y).dothis();

Marko M.


_______________________________________________
To unsubscribe, visit http://jedsoft.org/slang/mailinglists.html


[2006 date index] [2006 thread index]
[Thread Prev] [Thread Next]      [Date Prev] [Date Next]