www.digitalmars.com         C & C++   DMDScript  

D - [RT] Ramblings of a Mad Man: Let me cast a spell...

reply Berin Loritsch <bloritsch d-haven.org> writes:
The talk about casting and templates made me think of a feature that I am not
sure has been discussed in any language development, but I could definitely use
it.  It takes the concept of templates even further--removing the need for a
large majority of the type of castings that I have to perform.

Long and short of it is that I would suggest a strongly typed "properties" type
of object.  Before I get into the nitty gritty of what it does, let me first
explain the need:

In the Apache Avalon project, we supply components to client components using
a ServiceManager.  The ServiceManager provides a way to look up and retrieve
a type of component.  All the services are bound to a particular name, so any
time the client component looks up a particular name, it will be the same type
of component.  Period.  We would love to use generics, but in all known
implementations of generics, you can only assign types to all the objects
stored.  For instance:

map<string, void*>;

In C++ this would create a map where the key had to be a string, and the
returned value could be anything.  In Java we are not so lucky, the Map
object binds Objects to the lookup value and to the return value.  To be
fair, the Object type has all that the Map needs to determine the hashcode
value and whether two keys are the same.  Polymorphism is used to finetune
those details.

The problem is on the client side where I know what I am looking up, and
the type I need:

CrisisManager crisis = (CrisisManager)
         serviceManager.lookup(CrisisManager.ROLE);

Even with generics, this is the best I could hope for with the solutions
currently available.

What I *really* need is to bind a type to the lookup name so that when I
retern a value from a lookup service it will always return the same type
of object.  In fact if I can guarantee this, then I can solve most of my
needs for strong typing and losing the cast operator.

The solution would be sort of a dynamic struct.  Like dynamic arrays (already
implemented), the dynamic struct would add new members that have a strong name
and stong type bound to it.  Call it properties or something, I don't really
mind what the final name is:

properties foo;

// code to assign the properties
foo.bar<Baz> = newBaz();
foo.crisisManager<CrisisManager> = getCrisis();

// later on in the client code
void doClientThings(properties services)
{
     services.bar.doBazThing();
     services.crisisManager.findOpenCrises();

     // throws an IllegalAccess exception (it is unassigned)
     services.unassigned.illegal();
}

Any subsequent assignments to a particular type have to be of that type.
For example:

foo.bar<Bar> = newBar();

// throws an IllegalType exception (it is a Baz type, not a Bar type)
foo.bar = newBaz();

And trying to reassign a type is also illegal once it has been set:

foo.bar<Bar>;

// throws an IllegalOperation exception (it has already been identified)
foo.bar<SomethingElse>;


And to perfectly round out the entire proposal it would be even more killer to
make the dynamic struct readonly after a particular point.  For example, if
I have the container code set up this dynamic struct, I won't want any of the
clients to reassign the objects/components I have painstakenly added to it.
Nor would I want them to add new assignments.  So if there is a way to freeze
the thing, it would totally rock.  Perhaps a special purpose property that
once the boolean is changed the entire struct becomes hardened like this:

properties foo;
foo.bar<Baz> = newBaz();
foo.crisisManager<CrisisManager> = getCrisis();
foo.writeable = false;

// all of these throw IllegalAccess exception
foo.bar = anotherBaz();
foo.subjectManager<SubjectManager = getSubjects();
foo.writable = true;

Or perhaps a "method" would be the way to go.  Perhaps assigning it as a const
is enough.  Dunno.  However this thing would help out alot.

IMPLEMENTATION DETAILS
----------------------
This is only one of the many possible ways to implement this feature.
Internally this would be an map<string, struct{Class type; Object value;}> that
is hidden by the compiler.  (I am thinking easiest to implement from my POV).
A lookup would be translated to something like this:

struct{Class type; Object value;} entry = map[entryName];
userVariable = (entry.type)entry.value;

Something along those lines would be good enough.  This is not the only way to
implement this thing at all.  Perhaps you could come up with new and exciting
ways yourself.

CAVEAT
------
This does mean that type checking has to be done at runtime instead of compile
time.  This is an unavoidable side effect.  Perhaps some compile time checking


[RequiredEntry(example, foo)]
[RequiredEntry(example, bar)]
void myMethod(properties example)
{
     // no errors
     example.foo.doSomething();
     example.bar.doSomething();

     // compile time error
     example.baz.doSomething();
}

Also if those same attributes were available at runtime, it could help the
container code (i.e. initializing code) to build the properties object with
the expected values.  In my experience, any one client would only need a few
of these attributes.  Of course, it would be cumbersome to have to type all
these entries for every method that uses the type.  To that end, attribute sets
would be even better.  But that is another topic altogether.
Dec 04 2003
parent reply "Mark Brudnak" <malibrud provide.net> writes:
"Berin Loritsch" <bloritsch d-haven.org> wrote in message
news:bqned2$fgn$1 digitaldaemon.com...
 The talk about casting and templates made me think of a feature that I am
not
 sure has been discussed in any language development, but I could
definitely use
 it.  It takes the concept of templates even further--removing the need for
a
 large majority of the type of castings that I have to perform.

 Long and short of it is that I would suggest a strongly typed "properties"
type
 of object.  Before I get into the nitty gritty of what it does, let me
first
 explain the need:

 In the Apache Avalon project, we supply components to client components
using
 a ServiceManager.  The ServiceManager provides a way to look up and
retrieve
 a type of component.  All the services are bound to a particular name, so
any
 time the client component looks up a particular name, it will be the same
type
 of component.  Period.  We would love to use generics, but in all known
 implementations of generics, you can only assign types to all the objects
 stored.  For instance:

 map<string, void*>;

 In C++ this would create a map where the key had to be a string, and the
 returned value could be anything.  In Java we are not so lucky, the Map
 object binds Objects to the lookup value and to the return value.  To be
 fair, the Object type has all that the Map needs to determine the hashcode
 value and whether two keys are the same.  Polymorphism is used to finetune
 those details.

 The problem is on the client side where I know what I am looking up, and
 the type I need:

 CrisisManager crisis = (CrisisManager)
          serviceManager.lookup(CrisisManager.ROLE);

 Even with generics, this is the best I could hope for with the solutions
 currently available.

 What I *really* need is to bind a type to the lookup name so that when I
 retern a value from a lookup service it will always return the same type
 of object.  In fact if I can guarantee this, then I can solve most of my
 needs for strong typing and losing the cast operator.
What I think you are saying is that you would like to look up a type based on a string like this, class myClass = repository.lookup("aClassName") ; object anObject = myClass.new ; If this is what you mean, then you are talking about a metaclass, like Smalltalk? A class is just another object of type "MetaClass".
 The solution would be sort of a dynamic struct.  Like dynamic arrays
(already
 implemented), the dynamic struct would add new members that have a strong
name
 and stong type bound to it.  Call it properties or something, I don't
really
 mind what the final name is:
You can instantiate a meta class at run time to create a new class. class newClass = new class ; newClass.addInterface("foo") ; newClass.addInterface("bar") ;
 properties foo;

 // code to assign the properties
 foo.bar<Baz> = newBaz();
 foo.crisisManager<CrisisManager> = getCrisis();

 // later on in the client code
 void doClientThings(properties services)
 {
      services.bar.doBazThing();
      services.crisisManager.findOpenCrises();

      // throws an IllegalAccess exception (it is unassigned)
      services.unassigned.illegal();
 }

 Any subsequent assignments to a particular type have to be of that type.
 For example:

 foo.bar<Bar> = newBar();

 // throws an IllegalType exception (it is a Baz type, not a Bar type)
 foo.bar = newBaz();

 And trying to reassign a type is also illegal once it has been set:

 foo.bar<Bar>;

 // throws an IllegalOperation exception (it has already been identified)
 foo.bar<SomethingElse>;


 And to perfectly round out the entire proposal it would be even more
killer to
 make the dynamic struct readonly after a particular point.  For example,
if
 I have the container code set up this dynamic struct, I won't want any of
the
 clients to reassign the objects/components I have painstakenly added to
it.
 Nor would I want them to add new assignments.  So if there is a way to
freeze
 the thing, it would totally rock.  Perhaps a special purpose property that
 once the boolean is changed the entire struct becomes hardened like this:

 properties foo;
 foo.bar<Baz> = newBaz();
 foo.crisisManager<CrisisManager> = getCrisis();
 foo.writeable = false;
That is the beauty of access functions and properties. This feature does not need to be built into the language.
 // all of these throw IllegalAccess exception
 foo.bar = anotherBaz();
 foo.subjectManager<SubjectManager = getSubjects();
 foo.writable = true;

 Or perhaps a "method" would be the way to go.  Perhaps assigning it as a
const
 is enough.  Dunno.  However this thing would help out alot.

 IMPLEMENTATION DETAILS
 ----------------------
 This is only one of the many possible ways to implement this feature.
 Internally this would be an map<string, struct{Class type; Object value;}>
that
 is hidden by the compiler.  (I am thinking easiest to implement from my
POV).
 A lookup would be translated to something like this:

 struct{Class type; Object value;} entry = map[entryName];
 userVariable = (entry.type)entry.value;

 Something along those lines would be good enough.  This is not the only
way to
 implement this thing at all.  Perhaps you could come up with new and
exciting
 ways yourself.

 CAVEAT
 ------
 This does mean that type checking has to be done at runtime instead of
compile
 time.  This is an unavoidable side effect.  Perhaps some compile time
checking


 [RequiredEntry(example, foo)]
 [RequiredEntry(example, bar)]
 void myMethod(properties example)
 {
      // no errors
      example.foo.doSomething();
      example.bar.doSomething();

      // compile time error
      example.baz.doSomething();
 }

 Also if those same attributes were available at runtime, it could help the
 container code (i.e. initializing code) to build the properties object
with
 the expected values.  In my experience, any one client would only need a
few
 of these attributes.  Of course, it would be cumbersome to have to type
all
 these entries for every method that uses the type.  To that end, attribute
sets
 would be even better.  But that is another topic altogether.
Dec 05 2003
parent Berin Loritsch <bloritsch d-haven.org> writes:
Mark Brudnak wrote:
 "Berin Loritsch" <bloritsch d-haven.org> wrote in message
 news:bqned2$fgn$1 digitaldaemon.com...
 
The talk about casting and templates made me think of a feature that I am
not
sure has been discussed in any language development, but I could
definitely use
it.  It takes the concept of templates even further--removing the need for
What I *really* need is to bind a type to the lookup name so that when I
retern a value from a lookup service it will always return the same type
of object.  In fact if I can guarantee this, then I can solve most of my
needs for strong typing and losing the cast operator.
What I think you are saying is that you would like to look up a type based on a string like this, class myClass = repository.lookup("aClassName") ; object anObject = myClass.new ; If this is what you mean, then you are talking about a metaclass, like Smalltalk? A class is just another object of type "MetaClass".
Not quite. WHat I want is pretty much a dynamic struct with strong typing. Essentially, I want to have one class populate the struct and another class to use it. I am not trying to have the client class worry about instantiation of the new object. All I want to do to use the class is this: Crisis[] crises = myDynStruct.crisisManager.getCrises(); Connection conn = myDynStruct.dataSource.getConnection(); It is already populated by something else. THe important thing here is to get away from having to cast everything or pass it as a weaker type.
Dec 08 2003