On 18 juil. 06, at 07:33, Andreas Raab wrote: > Yes. Alternatively, if we had a "literal object/class" syntax this > would be very simple, too. Andreas could you explain what you mean by literal object/class Stef |
stéphane ducasse wrote:
> On 18 juil. 06, at 07:33, Andreas Raab wrote: >> Yes. Alternatively, if we had a "literal object/class" syntax this >> would be very simple, too. > > could you explain what you mean by literal object/class Simply put, instead of defining a heavy-weight class (like we have right now), you have syntactic support for an inline object definition, making it possible to do something like here: sorted := def SortedCollection [ sorts: a before: b [ ^ a < b ] ] The idea is that the we "def"ine an object (which also has an associated class anonymously derived from SortedCollection but that is besides the point here) and can override some methods right at this point. The main advantage is that the above makes class creation very light-weight, almost unnoticable (really only as the byproduct of creating an object with specialized behavior) which is very different from the current heavy-weight use of classes (requiring multiple context switches, names for the classes etc). This of course gets more interesting when you need more than single parametrized method but the above illustrates the basic idea. Cheers, - Andreas |
Andreas Raab wrote:
> This of course gets more interesting when you need more than single > parametrized method but the above illustrates the basic idea. The other interesting part is the scoping of free identifiers within methods in the literal-object. Does a literal-object close over its environment like a block? Like a closure? Not at all? How are literal-objects initialized? Do they have instance variables? There are *lots* of interesting variations in exactly *how* to treat free identifiers... The whole idea is, I think, a good one - blocks themselves (well, more properly, closures) become special-cased syntactic sugar: [stuff] ===> def Block [ value [ ^ stuff ] ] [:a | a + 1] ===> def Block [ value: a [ ^ a + 1 ] ] It also introduces the thorny notion of naming partial continuations. (As in, which continuation does ^ throw to?) Cheers, Tony |
Tony Garnock-Jones wrote:
> Andreas Raab wrote: >> This of course gets more interesting when you need more than single >> parametrized method but the above illustrates the basic idea. > > The other interesting part is the scoping of free identifiers within > methods in the literal-object. Does a literal-object close over its > environment like a block? Like a closure? Not at all? How are > literal-objects initialized? Do they have instance variables? > > There are *lots* of interesting variations in exactly *how* to treat > free identifiers... Actually I don't think so. Just be willing to make a few well-defined tradeoffs. Like: No accesses to the enclosing iVar scope. Send messages. For sending message we introduce an "outer" keyword just like we have "super" today. So you may have something like here: Morph>>makeMorphWithDefaultBounds: defaultBounds ^def Morph [ resetBounds [ bounds := defaultBounds expandBy: outer borderWidth. ] ] This is perfectly well-defined as far as the relationship between the inner and the outer iVar scope is concerned (e.g., no access to the outer scope). For the closure environment provided for the definition, I'd grant access to that (defaultBounds in the above) but without disambiguating shadowed variables (tough luck, rename the temp/arg if there is a conflict). Seems pretty simple, obvious, and well-defined to me. (and yes, this is not the first time I've been thinking about this issue ;-) > The whole idea is, I think, a good one - blocks themselves (well, more > properly, closures) become special-cased syntactic sugar: Exactly. It took me about ten years to grasp that methods are conceptually classes with the temps being the iVars of those classes and the contexts being their instances. > [:a | a + 1] ===> > > def Block [ > value: a [ > ^ a + 1 > ] > ] > > > > It also introduces the thorny notion of naming partial continuations. > (As in, which continuation does ^ throw to?) Same as today. The difference between block and method is arbitrary (always has been) and I'd go so far as to say: "a method is a block you can return to", e.g., make the "returnability" part of what defines a method. Practically, this always has been true just "the other way around", e.g., if you had a block that you wanted to be able to return to, you'd have to make this block into a method. Cheers, - Andreas |
Andreas Raab wrote:
> For sending message we introduce an "outer" keyword just like we have > "super" today. So you may have something like here: > > [...] > >> It also introduces the thorny notion of naming partial continuations. >> (As in, which continuation does ^ throw to?) > > Same as today. The difference between block and method is arbitrary > (always has been) and I'd go so far as to say: "a method is a block you > can return to", e.g., make the "returnability" part of what defines a > method. Well, both these solutions are practical and implementable; I still have some questions though: Firstly, wrt "outer" - what about someMethod ^ def Object [ otherMethod [ ^ def Object [ furtherMethod [ ^ outer service + 4 ]]] service [ ^ 4 ]] "outer" is ambiguous here. IMO, plain old lexical scoping (note: not references to ivars, just to temps and arguments) is good enough - since self is already available in each context to get what you want. someMethod | serviceProvider | serviceProvider := def Object [... ^ serviceProvider service + 4 ...] Actually, that's sort-of interesting: do the lexically-scoped variables (temps, arguments) become the instance-variables of the anonymous class? Secondly, regarding the distinction between blocks and methods: if "a method is a block you can return to" (do you mean from?) then blocks and methods are semantically different, and the syntactic equivalence I sketched in my last message doesn't hold. Could we instead use thisContext for finer control, and make ^ some kind of sugar for such use? someMethod | leave | leave := thisContext. someCondition ifFalse: [ leave returnValue: nil ]. ^ self complexComputation. (I guess uses of ^ would have to cause a binding at the outermost lexical level with the value of thisContext that occurs there.) Then ^ works as it usually does, throwing control back to the enclosing context of all the currently-visible text - as far out as you can see - and we get finer control for the complicated cases it's needed. Cheers, Tony |
Tony Garnock-Jones wrote:
> Could we instead use > thisContext for finer control, and make ^ some kind of sugar for such use? It turns out this is (of course!) already possible: someMethod | leave | leave := thisContext. leave return: 3. ^ 4 ... will always return 3. Lexical scoping can now be used to precisely target a particular context. The rule for exactly which context ^ targets (outermost visible? outermost named-method?) with literal-object syntax is a free choice, I guess. Hooray for fully reflective languages! Cheers, Tony |
Tony Garnock-Jones wrote:
> someMethod > | leave | > leave := thisContext. > leave return: 3. > ^ 4 Experimenting further, this works for blocks too, provided the blocks haven't been inlined. Perhaps mention of thisContext inside a block should disqualify it as a candidate for inlining? 1 + ([ thisContext return: 3 ] value) "returns 4" 1 + ((1 == 1) ifTrue: [ thisContext return: 3 ]) "returns 3" Cheers, Tony |
Free forum by Nabble | Edit this page |