Smalltalk syntax and flow control 
Author Message
 Smalltalk syntax and flow control

I am interested in your thoughts about the value of flow control as message
sends verses traditional flow control keywords.

I am writing a Smalltalk based scripting language, which has a working name
of Clarity.  The idea behind Clarity is that the syntax be clear, and the
lexer, parser, code generator and interpretor should be also as simple as
possible to implement. The Interpreter should be high quality with minimal
overhead.

Therefore there is a feedback loop in play in the design of the language.
1.    Design the syntax for human consumption (as clear as possible to the
reader)
2.    Build the lexer and parser
3.    Build the code generator and interpretor

If 2 or 3 is hard to do go back to 1. and redesign the syntax so that it is
still clear but easier to implement.

The first iteration went for fairly pure smalltalk syntax for flow control
.... ifTrue: [] if:False [] etc.
There are a number of problems with this approach.

1.    It quickly becomes clear that this is a pain in the rump to implement
effectively because of the overhead of block creation.  Now I know what some
of you will suggest - optimise the blocks in-line.  Well, this is only
possible if certain keywords such as ifTrue: are treated as immutable in
function - implementing ifTrue: with some other side effect is not possible
since no message will really be sent.

2.    Flow control is not really the responsibility of an object.  For
example, what is the behavior of a boolean object?  When I think of boolean
I think of logical values True False.  It is a real stretch in my mind to
think that the behaviour of boolean is to execute code.

3.    Locality of reference becomes a problem for the human reader.  For
example.
         [ lots of code - many lines ] on: Exception do: []

    At a personal level I dislike the fact that you cannot tell the purpose
of the block until a message is sent to the block - which may be much later.
Interpreting code (as a human) is much simpler if the context of the code is
known up front.

4.    How is "goto" to be implemented.
    Now before you say goto is evil, the simple fact is, that goto is the
clearest and most efficient method of implementing state machines - bar
none.  I will back this up with code if you disagree.

This is not to say I dislike blocks.  Code such as - list select: [ :x | x <
50 ] - is very elegent in my mind.  I will keep this kind of construct.

The consequence of this is that I am leaning toward a more traditional flow
control construct albeit with a smalltalk (block like) flavour.

For example:      if expression [ statements ] else [ statements ]
                         while expression [ statements ]
                        try [ statements ] except [ statements ]
                        try [ statements ] finally [ statements]

Thoughts and feedback welcome.

James Thorpe



Tue, 25 Oct 2005 11:30:38 GMT  
 Smalltalk syntax and flow control

Quote:

> The first iteration went for fairly pure smalltalk syntax for flow
> control .... ifTrue: [] if:False [] etc.

> 1.    It quickly becomes clear that this is a pain in the rump to
> implement effectively because of the overhead of block creation.  Now
> I know what some of you will suggest - optimise the blocks in-line.
> Well, this is only possible if certain keywords such as ifTrue: are
> treated as immutable in function

Is efficiency really *that* important for a scripting language ?  Compared to
simplicity, say ?  If so -- and it's your choice -- then how about special
casing, say:

    <an expression>
        ifTrue: [..code..]
        ifFalse: [...code...]

by executing it with code that looks like (using C syntax to point the
difference):

    tmp = <an expression>;
    if (tmp == true) { ... code .. }
    else if (tmp == false) { ... code ... }
    else { .. create blocks and send #ifTrue:ifFalse:' to tmp... }

which will be hardly less efficient in the common case, and not noticeably less
efficient in the uncommon case (where #ifTrue:ifFalse: isn't being sent to a
Boolean).

Quote:
> 2.    Flow control is not really the responsibility of an object.  For
> example, what is the behavior of a boolean object?  When I think of
> boolean I think of logical values True False.  It is a real stretch
> in my mind to think that the behaviour of boolean is to execute code.

Yes, I have a lot of sympathy with this.  Also it leads to very unintuitive
bracketing (nested []s and ()s) even for what *should* be simple cases.

OTOH, if you use a special syntax then you'd loose the smooth continuity
between user-defined flow-of-control constructions (#at:ifPresent: etc) and
language-defined syntax.  I don't like the discontinuity, so IMO a "clean"
language should either:
1)    not use special syntax for flow-of-control
or
2)    allow user defined syntax extensions.
Simplicity suggests that (1) is to be preferred.  (I've never understood why
people claim that Lisp macros are a plus point to the language -- it seems to
me (uninformed) that the need for them is symptomatic of a weakness in the
semantics.)

Incidentally, constructions like #at:ifAbsent: show that you'll *have* to solve
the problem of implementing blocks reasonably efficiently (whatever that means
for your context), so there's no obvious loss in using them for all
flow-of-control (possibly with optimisations like the one I mentioned above).

Returning to your point about true and false not naturally having
responsibility for flow-control.  If you feel strongly enough about that, then
maybe you could introduce special flow-of-control objects.  They'd have names
like 'if' and conditional code could be written (e.g)

    if true: <anExpression> do: [...code].

i.e. "if" would be a well-known object (in the way that true, false, and nil
are in Smalltalk) which responded to the protocol:
    #true:do:
    #true:do:else:
    #false:do:
    #false:do:else:
You'd have a similar object (of a different class) called 'while', and maybe a
(very) few others.  The *implementation* of If>>true:do: would be a VM
primitive (rather than being handled by polymorphism).  Since 'if' is a
well-known object, your compiler could inline all cases where #true:do: was
sent to a literal occurrences of 'if', and use a normal message send for any
other (presumably rare) cases.

(BTW that'd be easy to prototype in your current Smalltalk and see if you like
how the resultant code reads.)

Quote:
> 3.    Locality of reference becomes a problem for the human reader.
> For example.
>          [ lots of code - many lines ] on: Exception do: []

I don't agree here.  I'm *not* telling you "you shouldn't use long blocks of
code, so with well-written code this won't be a problem" (I think arguments
that take that form are invalid).  But I *do* think that long blocks are very
much the exception rather than the rule -- I haven't bothered to measure it,
but I doubt if one in a hundred is long enough to obscure the fact that the
block has an exception handler.  If such cases are the exception (no pun
intended) then you'd be optimising the wrong case by providing special syntax.

Quote:
> 4.    How is "goto" to be implemented.
>     Now before you say goto is evil, the simple fact is, that goto is
> the clearest and most efficient method of implementing state machines
> - bar none.  I will back this up with code if you disagree.

State machines are my favourite example in favour of goto too (the other strong
positive argument is for machine-generated code).  Do you really foresee
*enough* use for state machines in a scripting language, though ?  Would you be
better off providing a primitive of some sort that allowed you to express
state-machines directly (a case-switch construct perhaps) ?

I admit that I'd find it a very odd addition to a clean, simple,
Smalltalk-influenced scripting language.  It'd be very unexpected, mostly -- I
think -- because it's at the "wrong" level of abstraction.  It'd throw me off,
and quite possibly put me off the language.

Your choice though.

BTW someone (was it Travis ?) posted a goto implementation in vanilla Smalltalk
a little while ago.  Worth a giggle (and a google).

    -- chris



Tue, 25 Oct 2005 17:51:17 GMT  
 Smalltalk syntax and flow control
A syntaxic sugar I'd like to see in order to help No-Smalltalkers
would be to use a kind of prefix notion on selector.
For instance, it would be possible to write:
  if: (i < 2) then: [i := 4] else: [i := i +1]. "<=> ifTrue:ifFalse: "
  repeat: [expr] until: [condition]. "<=> expr. [condition] whileTrue:
[expr]. "
  mix: a with: b. "<=> (a mixWith: b) and <=> (b mixWith: a)".

this #if::then:else: method would be defined as the #ifTrue:ifFalse:
on a Boolean receiver.
True>>if:then: aBlock else: anotherBlock
        ^aBlock value.

So it remains a message call with a unique receiver object and
optional argument objects. Only the syntax used for the message call
is expanded.

It would be also nice to have a notion of sufix for a selector.
For instance:
 aCollection copyFrom: 1 :toEnd.

Collection>>copyFrom: n :toEnd
        ^self copyFrom: n to: self size

My two cents for a more readable and newbie friendly smalltalk...

D. Paxwax



Tue, 25 Oct 2005 21:55:55 GMT  
 Smalltalk syntax and flow control

Quote:
>4.    How is "goto" to be implemented.
>     Now before you say goto is evil, the simple fact is, that goto is the
> clearest and most efficient method of implementing state machines - bar
> none.  I will back this up with code if you disagree.

I'm not disagreeing, but I'd still like to see the code to back up the
statement.

Regards,

Peter van Rooijen
Amsterdam



Wed, 26 Oct 2005 00:53:54 GMT  
 Smalltalk syntax and flow control
Since the Smalltalk object world is an abstraction overlaid on top of
the physical environment of a CPU/Memory configuration, you have to
pick points in the abstraction to connect with the physical
environment, or nothing would ever get accomplished in the
abstraction. Pretty much all Smalltalk implementations use a special
encoding for SmallInteger (low-bit set to 1, etc). This is a
connection. If you have more bits to play with in the object
reference, you could also make Booleans and Characters 'primitivized'
in a similar manner.
Another connection is using primitive methods. I guess one could argue
that a 'purer' object abstraction could be achieved by have no
primitivized object references, and using only primitive methods in
SmallInteger. (Perhaps SmallInteger would actually hold a small
ByteArray whose values constitute the physical SmallInteger value.)
Primitive methods would then do the math. But the point is still the
pure abstraction must be broken at the point where the physical
connection is made. Optimizing #ifTrue:ifFalse by enforcing a Boolean
receiver is just another connection where the abstraction must be
broken. While a price is paid in the abstract world in in-lining code
for 'conditionals', the payback is of course increased speed in the
physical environment. But since the 'objectness' of a Boolean is so
close to a physical bit anyway, I don't see any great loss in assuming
the intent of #ifTrue:  messages. A Boolean, to me anyway, is of
little use EXCEPT to use it (eventually) as a receiver of #ifXXX
messages.  Perhaps my thinking is too limited here, but show me
another example of an eventual use of Boolean's other than being sent
#ifXXXX type messages.
The other connection I would argue is necessary is forcing #to:by:do
messages to be either inlined, or implemented as a VM call of some
kind. (Gotta put that 'goto' a loop by definition requires somewhere!)

Tim Coffey



Wed, 26 Oct 2005 01:28:44 GMT  
 Smalltalk syntax and flow control


Quote:
> A syntaxic sugar I'd like to see in order to help No-Smalltalkers
> would be to use a kind of prefix notion on selector.
> For instance, it would be possible to write:
>   if: (i < 2) then: [i := 4] else: [i := i +1]. "<=> ifTrue:ifFalse: "

It is pretty trivial to implement:

Check if:(i < 2) then: [i := 4] else: [i := i +1].

It requires no parser or compiler changes, just a "Check" object or class.
If the goal is to build some control flow messages which "look like" other
languages, this approach would work fine. Interestingly enough, this would
probably make the language look a lot more like COBOL or some scripting
languages like REXX than it already does. That's not necessarily a bad
thing, but I'll bet lots of people will think it is.

Quote:
>   repeat: [expr] until: [condition]. "<=> expr. [condition] whileTrue:
> [expr]. "

Likewise this could be:

Do repeat: [expr] until: [condition].

Do would also implement #repeat:while:, etc.

Quote:
>   mix: a with: b. "<=> (a mixWith: b) and <=> (b mixWith: a)".

This one is harder to implement in a straightforward readable manner
(without compiler changes) than the previous two. I could certainly
implement

Do mix: a with: b

through a DNU handler which redispatches mixWith: to a with an argument of
b. I'd want to change the IDE to know that implementers of mix:with:
included implementers of mixWith:. I can't think of a better receiver than
"Do" off the top of my head, but "Do" doesn't feel right either.

I don't ever remember having a problem switching to the Object-Action type
syntax of Smalltalk. So I've never really understood why people find it a
problem. Maybe it comes naturally to me because it is exactly how I
sometimes have to talk to my children: "Brandon, get down here and clean
up your room!" I do remember having a problem learning which IBM 360
assembler instructions went "left" and which went "right", though.

Quote:

> So it remains a message call with a unique receiver object and
> optional argument objects. Only the syntax used for the message call
> is expanded.

> It would be also nice to have a notion of sufix for a selector.
> For instance:
>  aCollection copyFrom: 1 :toEnd.

Maybe I'm just old, but I really don't see an advantage for this syntax
over:
aCollection copyToEndFrom: 1

Doug Swartz



Wed, 26 Oct 2005 10:04:27 GMT  
 Smalltalk syntax and flow control

Quote:
> I'm not disagreeing, but I'd still like to see the code to back up the
> statement.

I knew someone would. ;)

Try this on for size.  This is a non-trivial example taken from my lexer.

The beauty of using goto is that the CPU IP register implicitly carries the
state.
No state variables required.
We know we are in state X because we are executing code X.
The code is clean and easy to read, and executes efficiently.

This example would probably benefit from labels which are more
descriptive than stateN.

James.

/*
==========================================================================
 number:

 parse input number in following format:

 ([0-9]+(.[0-9]+)?(E(+|-)?[0-9]+)?) | (0x[0-9,A-F]+)

? = 0 or 1
+ = 1 or more

 this handles decimal integer, hex integer and floating point numbers (base
10)

 "goto" NOT considered harmful
==========================================================================
*/
void Lexer::number()
{
        // c contains initial digit
  token->token = Token::INT;
  put_char();
  if ( c != '0' ) goto state4;

  // possibly hex
  get_char();
  if ( isdigit( c ) )  { put_char(); goto state4; };
  if ( toupper( c ) == 'E' ) goto state7;
  if ( c == '.' )      goto state5;
  if ( toupper( c ) == 'X' ) { put_char(); goto state2; };
  if ( isalpha( c ) ) goto state10;
  goto state11;

 state2:  // hex number lead character - must be provided
  token->token = Token::HEXINT;
  get_char();
  if ( !isxdigit( c ) ) goto state10;
  put_char();
  // goto state3

 state3:  // remained of hex number
  get_char();
  if ( c == 0 ) goto state11;
  if ( !isxdigit( c ) ) {
   if ( isalpha( c )) goto state10;
   goto state11;
  }
  put_char();
  goto state3;

 state4:  // decimal integer or float
  get_char();
  if ( c == 0 ) goto state11;
  if ( c == '.' ) goto state5;
  if ( toupper( c ) == 'E' ) goto state7;
  if ( isalpha( c ) ) goto state10;
  if ( !isdigit( c ) ) goto state11;
  put_char();
  goto state4;

 state5:  // decimal point (.) must be followed by digit
  token->token = Token::REAL;
  put_char();
  get_char();
  if ( !isdigit( c ) ) goto state10;
  put_char();
  // goto state6

 state6:  // further decimal digits
  get_char();
  if ( c == 0 ) goto state11;
  if ( toupper( c ) == 'E' ) goto state7;
  if ( isalpha( c )) goto state10;
  if ( !isdigit( c )) goto state11;
  put_char();
  goto state6;

 state7:  // exponent (e) must be followed by digit or sign
  token->token = Token::REAL;
  put_char();
  get_char();
  if ( ( c == '-' ) || ( c == '+' ) ) { put_char(); goto state8;  };
  if ( isdigit( c ) ) { put_char(); goto state9; };
  goto state10;

 state8:  // exponent sign (+ or -) must be followed by digit
  get_char();
  if ( !isdigit( c ) ) goto state10;
  put_char();
  // goto state9

 state9: // exponent digits continued
  get_char();
  if ( isalpha( c ) ) goto state10;
  if ( !isdigit( c ) ) goto state11;
  put_char();
  goto state9;

 state10:  // error
  error( err_invalid_number );
 state11:  // exit

Quote:
}



Wed, 26 Oct 2005 13:51:57 GMT  
 Smalltalk syntax and flow control

Quote:
> 2.    Flow control is not really the responsibility of an object.  For
> example, what is the behavior of a boolean object?  When I think of
> boolean I think of logical values True False.  It is a real stretch
> in my mind to think that the behaviour of boolean is to execute code.

True and False don't know how to execute code. They just know how to send
a #value message.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,

                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."



Wed, 26 Oct 2005 19:28:00 GMT  
 Smalltalk syntax and flow control

Quote:

> I knew someone would. ;)

> Try this on for size.  This is a non-trivial example taken from my lexer.

> The beauty of using goto is that the CPU IP register implicitly carries
the
> state.
> No state variables required.
> We know we are in state X because we are executing code X.
> The code is clean and easy to read, and executes efficiently.

> This example would probably benefit from labels which are more
> descriptive than stateN.

I've attached the equivalent code generated by SmaCC
(http://www.refactory.com/Software/SmaCC/). Instead of using goto's, it uses
message sends and #whileTrue loops. I believe that it is just as readable as
your version. However, machine generated code's readability isn't as great
as concern as it is for normal code.

John Brant
-------------------------
scanForToken
 self step.
 (currentCharacter between: $1 and: $9) ifTrue: [^self scan1].
 currentCharacter == $0
  ifTrue:
   [self recordMatch: #(1).
   self step.
   currentCharacter isDigit ifTrue: [^self scan1].
   currentCharacter == $. ifTrue: [^self scan2].
   currentCharacter == $E ifTrue: [^self scan3].
   currentCharacter == $x
    ifTrue:
     [self step.
     (currentCharacter isDigit or: [currentCharacter between: $A and: $F])
      ifTrue:
       [
       [self recordMatch: #(1).
       self step.
       currentCharacter isDigit or: [currentCharacter between: $A and: $F]]
         whileTrue].
     ^self reportLastMatch]].
 ^self reportLastMatch

scan1
 [self recordMatch: #(1).
 self step.
 currentCharacter isDigit] whileTrue.
 currentCharacter == $. ifTrue: [^self scan2].
 currentCharacter == $E ifTrue: [^self scan3].
 ^self reportLastMatch

scan2
 self step.
 currentCharacter isDigit
  ifTrue:
   [
   [self recordMatch: #(1).
   self step.
   currentCharacter isDigit]
     whileTrue.
   currentCharacter == $E ifTrue: [^self scan3]].
 ^self reportLastMatch

scan3
 self step.
 (currentCharacter == $+ or: [currentCharacter == $-]) ifTrue: [self step].
 currentCharacter isDigit
  ifTrue:
   [
   [self recordMatch: #(1).
   self step.
   currentCharacter isDigit]
     whileTrue].
 ^self reportLastMatch



Wed, 26 Oct 2005 23:21:43 GMT  
 Smalltalk syntax and flow control
John,

I agree that this is nice and clear.  Not as efficient as "goto" however.  

In a procedural language such as C/C++ you code would incur the overhead of
stack frame creation, and pushing and popping arguements to procedures
scan1, scan2 and scan3.

Of course Smalltalk is more costly yet again.  

James.



Thu, 27 Oct 2005 21:06:45 GMT  
 Smalltalk syntax and flow control
Saying "execute code" was clumsy.  Let me rephrase.

It is a real stretch in my mind to think that the behaviour of boolean is to
get the value or another object. :)

James.

Quote:


>> 2.    Flow control is not really the responsibility of an object.  For
>> example, what is the behavior of a boolean object?  When I think of
>> boolean I think of logical values True False.  It is a real stretch
>> in my mind to think that the behaviour of boolean is to execute code.

> True and False don't know how to execute code. They just know how to send
> a #value message.

>   Dave Harris, Nottingham, UK | "Weave a circle round him thrice,

>                               |  For he on honey dew hath fed
>  http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."



Thu, 27 Oct 2005 21:13:16 GMT  
 Smalltalk syntax and flow control

That should read "of another object"



Thu, 27 Oct 2005 21:14:03 GMT  
 Smalltalk syntax and flow control
Chris,

Thank you for the thoughtful reply.  Funnily enough, I had already
considered much of what you had to say.

Quote:


>> The first iteration went for fairly pure smalltalk syntax for flow
>> control .... ifTrue: [] if:False [] etc.

>> 1.    It quickly becomes clear that this is a pain in the rump to
>> implement effectively because of the overhead of block creation.  Now
>> I know what some of you will suggest - optimise the blocks in-line.
>> Well, this is only possible if certain keywords such as ifTrue: are
>> treated as immutable in function

> Is efficiency really *that* important for a scripting language

To me it is.  It is one of the components of "elegance".  I don't believe
that performance and scripting are mutually exclusive.  I consider
languages such as Python, Ruby, PHP etc as scripting languages.  Given
their usage in web sites, and other multi-user environments, efficiency is
relatively important.

Quote:
> ?  Compared
> to
> simplicity, say ?  If so -- and it's your choice -- then how about special
> casing, say:

>     <an expression>
>         ifTrue: [..code..]
>         ifFalse: [...code...]

> by executing it with code that looks like (using C syntax to point the
> difference):

>     tmp = <an expression>;
>     if (tmp == true) { ... code .. }
>     else if (tmp == false) { ... code ... }
>     else { .. create blocks and send #ifTrue:ifFalse:' to tmp... }

> which will be hardly less efficient in the common case, and not noticeably
> less efficient in the uncommon case (where #ifTrue:ifFalse: isn't being
> sent to a Boolean).

I had considered this approach.  Just as others are uncomfortable about not
treating everything as an object, I am uncomfortable in having to deal with
special cases or special classes of object.  In your example, you are
suggesting that 1 syntax leads to 2 sets of symantics based on the object
type.

In the longer term I would solve this particular problem by type analysis
and getting rid of the dynamic message send altogether.  This is not
realistic for a first cut.

By adding keywords if, else, while, ..., no blocks ever need to be created
for these constructs.  Syntax always matches symantics.

Quote:
>> 2.    Flow control is not really the responsibility of an object.  For
>> example, what is the behavior of a boolean object?  When I think of
>> boolean I think of logical values True False.  It is a real stretch
>> in my mind to think that the behaviour of boolean is to execute code.

> Yes, I have a lot of sympathy with this.  Also it leads to very
> unintuitive bracketing (nested []s and ()s) even for what *should* be
> simple cases.

I wonder why most boolean functions "and", "or", etc were implemented as
keywords.  Having boolean/arithmetic operators a la C/C++ would have
simplified boolean expressions in Smalltalk enormously.

Quote:
> OTOH, if you use a special syntax then you'd loose the smooth continuity
> between user-defined flow-of-control constructions (#at:ifPresent: etc)
> and
> language-defined syntax.  I don't like the discontinuity, so IMO a "clean"
> language should either:
> 1)    not use special syntax for flow-of-control
> or
> 2)    allow user defined syntax extensions.
> Simplicity suggests that (1) is to be preferred.  (I've never understood
> why people claim that Lisp macros are a plus point to the language -- it
> seems to me (uninformed) that the need for them is symptomatic of a
> weakness in the semantics.)

Yes I accept the continuity issue.  However, I would suggest that having
specific flow control syntax (especially exeception syntax) may (would?)
lead to a slightly different formulation of things such as #at:ifPresent,
and therefore the discontinuity would be less than you would initially
think.

Also there are some things in an object oriented universe which are really
not well handled at all by objects.  You may be familiar with the
development of Aspect Oriented languages which seek to address some of
these issues.  

Quote:
> Incidentally, constructions like #at:ifAbsent: show that you'll *have* to
> solve the problem of implementing blocks reasonably efficiently (whatever
> that means for your context), so there's no obvious loss in using them for
> all flow-of-control (possibly with optimisations like the one I mentioned
> above).

Yep. I agree.  Block are good. Efficient block are better. However, having
to create blocks unnecessarily is an overhead I can do without.  Syntaxic
changes eliminating many blocks remains my preferred option.

- Show quoted text -

Quote:
> Returning to your point about true and false not naturally having
> responsibility for flow-control.  If you feel strongly enough about that,
> then
> maybe you could introduce special flow-of-control objects.  They'd have
> names like 'if' and conditional code could be written (e.g)

>     if true: <anExpression> do: [...code].

> i.e. "if" would be a well-known object (in the way that true, false, and
> nil are in Smalltalk) which responded to the protocol:
>     #true:do:
>     #true:do:else:
>     #false:do:
>     #false:do:else:
> You'd have a similar object (of a different class) called 'while', and
> maybe a
> (very) few others.  The *implementation* of If>>true:do: would be a VM
> primitive (rather than being handled by polymorphism).  Since 'if' is a
> well-known object, your compiler could inline all cases where #true:do:
> was sent to a literal occurrences of 'if', and use a normal message send
> for any other (presumably rare) cases.

> (BTW that'd be easy to prototype in your current Smalltalk and see if you
> like how the resultant code reads.)

I prefer new syntax to fudging syntax.

Quote:
>> 3.    Locality of reference becomes a problem for the human reader.
>> For example.
>>          [ lots of code - many lines ] on: Exception do: []

> I don't agree here.  I'm *not* telling you "you shouldn't use long blocks
> of code, so with well-written code this won't be a problem" (I think
> arguments
> that take that form are invalid).  But I *do* think that long blocks are
> very much the exception rather than the rule -- I haven't bothered to
> measure it, but I doubt if one in a hundred is long enough to obscure the
> fact that the
> block has an exception handler.  If such cases are the exception (no pun
> intended) then you'd be optimising the wrong case by providing special
> syntax.

I like having the context for any code known upfront.

Quote:
>> 4.    How is "goto" to be implemented.
>>     Now before you say goto is evil, the simple fact is, that goto is
>> the clearest and most efficient method of implementing state machines
>> - bar none.  I will back this up with code if you disagree.

> State machines are my favourite example in favour of goto too (the other
> strong
> positive argument is for machine-generated code).  Do you really foresee
> *enough* use for state machines in a scripting language, though ?  Would
> you be better off providing a primitive of some sort that allowed you to
> express state-machines directly (a case-switch construct perhaps) ?

The amount of parsing I do is actually quite considerable.  On a day to day
basis there is CSV, HTML, XML, and less often others.  Given the importance
of HTML and XML today, and other unknown formats tomorrow, I like to have
the mechanisms to write fast parsers.

Additionally, it is amazing how many process problems can be expressed as
state machines - for which goto is ideal

Quote:
> I admit that I'd find it a very odd addition to a clean, simple,
> Smalltalk-influenced scripting language.  It'd be very unexpected, mostly
> -- I
> think -- because it's at the "wrong" level of abstraction.  It'd throw me
> off, and quite possibly put me off the language.

I am not trying to convert you :).  I really just wanted some good feedback
on my thinking to date.  I wanted to ensure that I had not missed something
that overwhelmingly suggests I should use object based flow control.

- Show quoted text -

Quote:
> Your choice though.

> BTW someone (was it Travis ?) posted a goto implementation in vanilla
> Smalltalk
> a little while ago.  Worth a giggle (and a google).

>     -- chris



Fri, 28 Oct 2005 02:45:58 GMT  
 Smalltalk syntax and flow control

Quote:
> >     tmp = <an expression>;
> >     if (tmp == true) { ... code .. }
> >     else if (tmp == false) { ... code ... }
> >     else { .. create blocks and send #ifTrue:ifFalse:' to tmp... }

> I had considered this approach.  Just as others are uncomfortable about
> not treating everything as an object, I am uncomfortable in having
> to deal with special cases or special classes of object.  In
> your example, you are suggesting that 1 syntax leads to 2 sets of
> symantics based on the object type.

This seems like a low-level notion of semantics. I would say that the
details of dispatch, or whether blocks are created, should not appear on
the user's radar and so are not semantic differences. The program behaves
"the same" whether this optimisation is done or not.

Indeed, unless you hide the concrete implementation behind an abstract
model of semantics, you won't be able to optimise at all. That would
defeat your goal of efficiency. Your implementation, once written, will be
cast in stone.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,

                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."



Thu, 27 Oct 2005 21:47:00 GMT  
 Smalltalk syntax and flow control

Quote:
> Saying "execute code" was clumsy.  Let me rephrase.

> It is a real stretch in my mind to think that the behaviour of boolean
> is to get the value or another object. :)

That strikes me as bizarre. So do you also disallow:

    ^a and: b

since that also sends #value ? Personally, I see logical expressions as
being as much part of boolean as addition is part of integer. And I have
no qualms about using blocks and #value when non-strict arguments (aka
lazy evaluation) are needed, in /any/ class.

And if we allow the above, it seems churlish to deny:

    ^a ifTrue: b

How do you feel about user-defined control constructs? Eg things like:

    myWeirdCollection do: [each| "..."]

Do you think it is OK for Collection>>do: to get the value of another
object? Do you want booleans to be second-class objects, not allowed to do
the things which collections do?

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,

                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."



Thu, 27 Oct 2005 21:47:00 GMT  
 
 [ 25 post ]  Go to page: [1] [2]

 Relevant Pages 

1. Syntax Questions for a new language with somewhat Smalltalk-like syntax

2. Program Flow Control

3. program flow control

4. PROPOSAL: New Control Flow Words

5. RFI: Control-flow Stack

6. Control-flow stack which may not exist

7. Q. WHAT is the Control Flow Stack?

8. Where is the Control Flow Stack?

9. Program Flow Control Structures

10. control flow too complicated (was: FOR...NEXT in Eforth)

11. Who invented the control-flow stack?

12. control flow too complicated (was: FOR...NEXT in Eforth)

 

 
Powered by phpBB® Forum Software