I just prototyped own Prototypes hackish implementation. :)
Comparing to Russel's implementation [1] ,
there is no pressure of inheriting from a Behavior.
A clean prototype inherits from nothing , but gains a behavior from its class.
The prototype reference is stateless object, carrying no state.
Instead, its class reference points to a 'stateful prototype', which holding
'prototype methodDict format' ivars to make VM happy
as well as slots and couple of other things.
The slots can be added on the fly , without using #become: ,
since a slot placeholder is a method in method dictionary! :)
(this btw, makes prototype slots access speed nearly same as for any
other smalltalk object using accessor).
All things, like replacing a prototype's prototype slot is working.
To communicate with 'stateful prototype' i'm using the hack, provided
by VM - by sending a #class message
to receiver, which bypassing a standard lookup procedure. :)
Traits naturally fit well with prototypes, and i using them from the
very starting.
An initial prototype object constructed using traits to fill initial behavior:
initialize
| proto |
methodDict := MethodDictionary new.
binding := nil->self.
format := 2. "Object format"
prototype := nil.
"Add method from TBasicPrototype trait"
TBasicPrototype methodDict do: [:method |
self addMethod: (method clone methodClass: self)
].
statelessOp := self primNew.
"Add the TTraitInheritable trait"
proto := statelessOp new.
TTraitInheritable methodDict do: [:method |
proto addMethod: method
].
^ proto new
the resulting prototype is more-or-less ready for use, having
TBasicPrototype -> TTraitInheritable prototype as delegates.
You can start experimenting with it:
| proto |
proto := PrototypeFactory new.
proto inheritTrait: TPrintable.
proto prototype "print it"
a Prototype( *prototype: a Prototype #traits: a Set(TPrintable) (a
Prototype>>#fullPrintString "a CompiledMethod(3976)") (a
Prototype>>#isKindOf: "a CompiledMethod(3228)") (a
Prototype>>#printOn: "a CompiledMethod(3398)") (a
Prototype>>#printString "a CompiledMethod(122)") (a
Prototype>>#printStringLimitedTo: "a CompiledMethod(367)") )
next, make a Point .
proto importTrait: TPoint.
point := proto new initialize.
point x: 50.
point "print it"
a Prototype( *prototype: a Prototype #x: 50 #y: 0 )
Take a closer look, at 'magic' in
TTraitInheritable>>traits
and
TPoint>>initialize
and why it is possible (PrototypeFactory>>installSlot:value:)
Of course, implementation is not complete. Just a proof of concept :)
Have fun :)
[1]
http://russell-allen.com/squeak/prototypes/--
Best regards,
Igor Stasenko AKA sig.