[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: macros / code construction (and assignment)




The first part of this message is a reply to Dave's and argues about
assignment.  In my last message I just wanted to use the assignment issue
as an example to justify a generic code construction mechanism.  The second
part tries to clarify on that.


--------------------------------------------------------------------------
PART 1:

Dave wrote:

> containers are an appealingly intuitive notion,
Sure, I want assignment to feel like that.

> and so I am happy to ground out where it does.
Only it doesn't ground out at containers, it grounds out at the assignment
primitive.

> Going deeper does not seem to me to buy so much.
As has been pointed out, it buys you a cleaner design and thereby more power.

> We have had lots of discussions about assignment, [...]
There was one on this list which I am gonna quote from:

> From: Randall.Smith@eng.sun.com (Randy Smith)
> Date: Thu, 7 Apr 1994 18:08:10 +0800
> 
> You have tripped upon what I think is a small, sore wart on the current
> semantics of assignment.

> So what you might write today as
>         (| x <- 7 |),
> essentially the same as
>         (| x      = 7.
>            x: arg = <-.       |),
> would become
>         (| x       = 7.
>            x: arg  = <-['x']. |).

> Another up side [...] is that the story of what <-[x] means is tidy: 
>     x: arg  = <-['x'] 
> is like
>     x: arg  = ( (reflect: self) at: 'x' Put: (reflect: arg) IfFail: [error]).

This looks (as I said) very similar to what I proposed:
((reflect: self) slot: 'x') store: arg

This way, it does indeed ground out at a container, namely the slot.
[ Where does the comma belong, here --------------^       ^-- or there? ]

The (putative) Downsides:

> 1] Today when you see an assignment slot in an object (| x <- 7 |), you
> know that there are two slots, and that x: is not trapped: it is
> guaranteed to contain "<-".  This simplifies the browsing task facing
> the programmer.

That's no downside.  Assumptions about the implementation of an abstraction
are always bad.

> 2] What is the scope of the x in <-['x'] ? Can it only assign to the x
> slot in this object? Or can it assign to a slot in some other parent or
> maybe any object in principle? Some say the former is a reasonable

The slot must not be referred to by name but directly.  Reify slots, or at
least, make it feel as if they were!  Some effects of that might surprise
you but these surprises are what I want: for example you could move the
slot to a parent and make it a shared data slot, assignment would still
work.


--------------------------------------------------------------------------
PART 2:

As Randy pointed out, (| x <- 7 |) means (| x = 7. x: arg = <-. |).  This
kind of syntactic sugar is indispensable.  That's what macros provide:
syntactic sugar.

When I do Lisp, I very often use a macro to essentially get an inline
function.  Since backquoting is awkward and error-prone, I defined a
`definline' macro, which in turn makes defining macros a breeze.  It is
this kind of power that I want.  To be able to boost the language with my
own idioms.

Imagine having to write the above every time you want an assignable slot,
horrible!  Now, with reflection, we can invent very powerful extensions to
the base language.  But using them without syntactic sugar is not feasible,
it's just too awkward:
(| x  = 7.
   x: = (|:arg| ((reflect: self) slot: 'x') store: arg). |)

(that's still buggy, don't mention.)

So we need a way to create our own syntactic sweets.

(|x = 7. x: = := x.|) might be the way that would look like,
where `:=' refers to a global macro that does the right thing.

L. Peter Deutsch (LPD) mentioned that self's syntax is a problem for code
manipulation.  This is so obvious to me that I forgot to mention it on my
list of Self's weaknesses.  I can't say I hate it, but it's crap compared
to the beauty of Scheme.  In my opinion, code beauty is a value, and the
ability to make idoms look `just right' enables one to choose the beauty
criterion oneself.

LPD> [code as data] works so well in Lisp because Lisp is so simple.

Which is a virtue.

[An aside:
 LPD> two non-terminals (atoms and numbers) and one terminal (list cells)
 Huh?  The other way round, I should say, and: aren't numbers atoms?
 ]
 
Trying to explain what I do, I often explain to people why Self doesn't
need explicit control structures.  Then I get to show the different syntax
for `if'.  And most of them instantly object to `bool if: then False:
else'.  Everybody (including me) wants `if bool then else'.  So I wouldn't
call macros `efficiency hacks' (LPD), rather `convenience hacks'.

The syntax used by the end user may be whatever she finds convenient,
independent of the syntax used by the system designer.  The Self syntax is
not particularly convenient, to some even repellent.  The designer will
probably best use a syntax that maps one-to-one on the language concepts
and provides a suitable base for structured code manipulation.  The Self
syntax does neither (see the paper on ASTs), it seems to stem from the
authors' Smalltalk experience.  Therefore it should be dropped in favor of
a fully parenthesized one.

Rainer