Smalltalk the Hub
Return to home page
Comments Loading...
2003-09-15

I'm glad to have stirred up some interest with my piece on first class classes in Smalltalk. So I'd like to try and answer some of the questions posed via various mediums.

Firstly, water, yeah I'd love to talk to you about this for your Slate language. I think it has some unique potentials. Why were you so kurt with Misolin last night?

Clarence, wow!, there is one person I know of who _has_ done more with the meta class structure for real, that's David Simmons with S#. He has interfaces and modules, etc, by having subclasses of the meta class class.

Talios, yeah, you're hitting it on the nail there. Condence the reflection API and it's easier to make new kinds of classes that continue to behave within the existing tools. Traits would go a long way towards helping this!

James, SqueakDotNet falls in to the same category as all the other 'wrapper' systems that we use in Smalltalk. The proxy pattern works very very well and we've been using it to do some amazing things for years now. But there's one proxy pattern that is used core in all Smalltalk's that we rarely think about. Message-Dispatch. That guy is the ultimate proxy pattern. Why are we re-inventing this pattern over and over on top of the one Smalltalk already provides?

Alan. Spot on (as if there'd be anything less from Mr. Knight). What you've said in your comment is this: "Smalltalk can do this and to a degree already is". But to address your main question, what's the difference between a proxy class + a marshaller/demarshaller + support structure classes and a first class class object in Smalltalk?

Essentially it comes down to how you can subclass it and use its instance variables. Did you know you can directly reference an environment variable in your running process by saving the reference to it and having it undeclared? - this says to me "We can bind from anywhere".. so why not bind to abstract mappings on the class itself?

Lets take a C structure that has several variables on it. Something needs to map them to memory and allow it to know the offsets, but past that, the only real difference between that and a Smalltalk instance is that the offsets are irregular. We now have the variable names too.. why can't I write methods that talk to those instance variable names directly. With existing wrapper systems, you'd need to call a method to retrieve the variable instead of referencing it directly. What's wrong with this? - well, it's not Smalltalk.

Part of Smalltalk is being about to type 'myVariable' and access it within it's compiled scope when your method is run. When you start wrapping up other peoples memory structures, you lose that. I'll just veer off course for a bit now.. is it cheaper to marshal/unmarshal, or to store in to memory in the native format to begin with? What are the costs involved:

To make it work, you end up needing a simple proxy object anyway, so that you can keep track of structures that are managed by your VM. That doesn't mean much, it just means that the same 'meta information' about an instance that you have for a regular object is kept for a uniquely-structured object. This solves the Interrnal-External GC boundary problem.

To tug my thoughts in another direction. What is my problem with the C Smalltalk divide? - I can write methods easier in Smalltalk, but I can control structures easier in C. People spend a lot of time inventing new ways to structure information in memory. It's easy to 'prototype' by having an index of instance variables for your structure, but for people outside the Smalltalk world, this just never happens.

New cost: Shape changes. It's harder to morph a uniquely-shaped instance from one shape to another. But it is solveable. It actually seems to me that in VW, this doesn't normally occur any way. Shape changes happen, but instance variable data does not relocate. Here's an idea instead: Let's not. Why don't we make the 'old' shape become one of those temporary classes, and the new shape becomes referenceable from a Namespace as a class.

This suggests that an instance has not just a class, but a shape! A class gives it behaviour (which could be a combination of methods and traits?) and a shape gives it.. well, it's shape. The most basic shape is the indexed instance variables. The second most basic is named instance variables (a hash table/dictionary). Then from there you can do all kinds of odd things.

What else does this break? well, people who blindly use instVarAt: and instVarAt:put: - this assumes an indexed memory structure. Why haven't we always had instVarNamed: and instVarNamed:put: ? - and if we did and dropped the 'at:' versions, why not have store/retrieve of instance variables call them? - if we did that, then it's a simple matter of delegating them to your Shape class.

I may be getting a little bit ahead of myself now. But the Shape class can also be linked in to the way GCing works, to allow traversal of unique shapes and find object pointers in them.

Okay, lets step back a second,.. what does all this REALLY mean? It means we pull MORE stuff out of the VM and move it in to Smalltalk code. This is a good thing IMHO!. But if we were storing in to unique structures at runtime, no marshal/unmarshal is required to talk to an external system, to them you're just like everything else in the system. Please note: I'm not suggesting we 'import' methods from external systems, just let unique structures live as first class citizens in a Smalltalk VM. I suggest the DNU trick is still valid for calling remote methods.

I'm very sure there will be more on this to come...