Defining methods within a block

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Defining methods within a block

Rob Hoelz
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
Reply | Threaded
Open this post in threaded view
|

Re: Defining methods within a block

Paolo Bonzini

> 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