Saving morphs to file

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

Re: Saving morphs to file

stéphane ducasse-2

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


Reply | Threaded
Open this post in threaded view
|

Re: Saving morphs to file

Andreas.Raab
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


Reply | Threaded
Open this post in threaded view
|

Re: Literal object syntax

Tony Garnock-Jones-2
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


Reply | Threaded
Open this post in threaded view
|

Re: Literal object syntax

Andreas.Raab
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


Reply | Threaded
Open this post in threaded view
|

Re: Literal object syntax

Tony Garnock-Jones-2
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


Reply | Threaded
Open this post in threaded view
|

Re: Literal object syntax

Tony Garnock-Jones-2
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


Reply | Threaded
Open this post in threaded view
|

Re: Literal object syntax

Tony Garnock-Jones-2
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

12