Hello Smalltalkers,
I've been trying to immerse myself in Smalltalk for a project I'm working on, so I've been dabbling in the reflective and introspective capabilities of the GNU Smalltalk system. I've written a method for Object that mimics Ruby's "Object-specific class" feature (if you're not familiar with it, here's a pretty good explanation: http://www.ruby-doc.org/docs/ProgrammingRuby/html/classes.html#UB), and here it is, along with some example usage code: !Object methodsFor: 'my methods'! objectSpecificMethod: aMethod | klass className newClassName | klass := self class. className := klass name. newClassName := className , '_1'. "This will have to be changed" klass subclass: (newClassName asSymbol) instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: (klass category). (Smalltalk at: (newClassName asSymbol)) compile: aMethod. self changeClassTo: (Smalltalk at: (newClassName asSymbol)). ^self. ! ! |obj| obj := Foo new: 1 next: 2 last: 3. Transcript print: (obj doStuff: 6); cr. obj objectSpecificMethod: ' doStuff: arg ^(three + arg). '. Transcript print: (obj doStuff: 6); cr. My question is this: Instead of providing Object#objectSpecificMethod a string, would it be possible to provide it a block? How would one define a method within a block? I tried obj objectSpecificMethod: [ doStuff: arg ^(three + args). ]. but that generates a syntax error. Please let me know what you think. Thanks, Rob Hoelz _______________________________________________ help-smalltalk mailing list [hidden email] http://lists.gnu.org/mailman/listinfo/help-smalltalk |
> My question is this: Instead of providing Object#objectSpecificMethod > a string, would it be possible to provide it a block? Yes, but it is not in the basic class library. You can define a subclass of CompiledMethod that will forward the message to a block. Something like this (I'm using 2.95x syntax; if you have an older version as I think, it will be easy to convert it to the old syntax; or it will whet your appetite so you'll download the latest version and compile it). CompiledMethod subclass: MethodBlock [ | closure | MethodBlock class >> on: aBlock [ ^(self numArgs: aBlock numArgs) closure: aBlock ] closure: aBlock [ closure := aBlock ] valueWithReceiver: anObject withArguments: args [ ^closure valueWithArguments: args ] ] Behavior subclass: ObjectSpecificBehavior [ Behavior >> isObjectSpecific [ ^false ] isObjectSpecific [ ^true ] ] Object extend [ implantObjectSpecificBehavior [ | subclass | self class isObjectSpecific ifFalse: [ subclass := ObjectSpecificBehavior new. subclass superclass: self class. self changeClassTo: subclass ] ] objectSpecificMethod: aString [ self implantObjectSpecificBehavior. self class compile: aString ] objectSpecificMethod: selector do: aBlock [ self implantObjectSpecificBehavior. self class addSelector: selector withMethod: (MethodBlock on: aBlock ) ] ] | obj | obj := 1 to: 20. obj objectSpecificMethod: #every: do: [ :n | obj atAll: (n to: obj size by: 3) ]. (obj every: 3) printNl "(3 6 9 12 15 18 )" As you can see from the example, blocks don't have access to "self" and instance variables available. This is by design. In Ruby, @abc syntax is resolved at run-time, while in Smalltalk it is resolved at compile-time (you need to know the list of instance variables at compile-time). On the other hand, 99% of the time you can access self from the enclosing environment ("obj" in the example), and you gain the possibility to access the enclosing environment's "self" and instance variables. Paolo _______________________________________________ help-smalltalk mailing list [hidden email] http://lists.gnu.org/mailman/listinfo/help-smalltalk |
Free forum by Nabble | Edit this page |