Comments on: Explicit EvaluationTerminator

Carl Sassenrath, CTO
REBOL Technologies
14-Apr-2007 0:28 GMT

Article #0086
Main page || Index || Prior Article [0085] || Next Article [0087] || 35 Comments || Send feedback

Here's one you will enjoy debating on Saturday night with friends in front of a warm fire while it is still snowing outside...

Should REBOL provide a terminator to argument evaluation?

Please Note

I've been thinking about this for more than 8 years, and I've never reached a positive conclusion. (Lol)

Is this noise? Or, is it useful?

I'm writing it on this blog to see if you can help me conclude one way or the other regarding its validity. (And please excuse my sanity if we've already debated and concluded on this topic. "My brain cache overflowth.")

Imagine you have a function defined as:

afunc: func [a b] [...]

When evaluated, you provide its actual arguments:

afunc 1 "test"

The termination point of the argument evaluation is implied by the function's arity (its number of arguments), not by the syntax of its usage.

So, if you write:

afunc 1

Then REBOL keeps looking for the b argument... even in the case:

afunc 1
if find block value [...]

But, that is actually valid and useful in REBOL. You are allowed to write:

afunc 1 if find block value [...]

So, if you need to enforce evaluation termination, you can do so a few ways:

do [afunc 1 "test"]

which you can also write as:

(afunc 1 "test")

And, don't forget:

apply :afunc [1 "test"]

However, another approach would be to allow an explicit terminator. It might look like this:

afunc 1 .

The . (dot or period) works much like that found in English or other human languages. It tells the interpreter to stop evaluating arguments for the most recent function and proceed with the reduction.

The dot here is not really syntactical like that of the semicolon (;) found in other languages. It is actually part of the expression. It is a semantically-based terminator.

It is possible that we could use the comma instead, just to avoid hard-to-find typos like:

afunc value.

Here the dot is part of the word, not a separate symbol. However, comma has never been allowed in words, so:

afunc value,

would be made the same as:

afunc value ,

The primary ambiguity would become:

afunc 123,

but, I think that is a small problem.

Note that a side-effect of the comma expression termination is that you might also find it of use in data as well as code.



15-Apr-2007 0:39:49
I haven't run into the termination problem to date. Is there something you can do with a terminator that you can't do without it? If there isn't, I see no need to add it.

I used to tell friends during REBOL demos, "We don't need no stinkin' semicolons." Not sure we need periods either.

15-Apr-2007 3:52:20
I must say that I would appreciate the coma. In my dialect I have problem, how to separate function args:
;I define functions as in Rebol

aFunc: func[a b][...]

;but I'm using paren for args, which are without separators

aFunc(1 2) ;or aFunc(a b)

;and here comes my problem... how to separate args, ;if I want to use func as an argument ;I cannot write this, as it would be recognized as 3 args for aFunc

aFunc(anotherFunc() b)

;so I use to enclose the func into another paren

aFunc((anotherFunc()) b)

;which I don't like, but don't know other way how to deal with this, ;if I don't want to know what functions are defined, ;in which contexts and how much args they need.

;so.. with comma I could write: aFunc(anotherFunc(), b)

I'm not sure if I need it in Rebol itself. I was talking about making dialects (loaded block based parsing).
15-Apr-2007 3:58:56
If I ever needed optional trailing arguments, I'd be quite happy with the do-block format as suggested. It is consistent with the optional argument on 'return:

f: func [] [return]
unset? f
== true

I'd rather not see the language cluttered with a bit of synax that would rarely be used.

I assume the "value" passed into a function of a non-existent argument would be none?

   f: func [a b c] [print c]
   do [f 1 2]
  == none
15-Apr-2007 4:19:54
I think that using blocks or parantheses is actually more readable than a sudden . in the middle of the code, because it could look like a typo.

Alternatively, provide a real word as a terminator, such as END or STOP. Perhaps a specific terminator! datatype?

John Niclasen
15-Apr-2007 4:48:07
I think, adding an evaluation terminator will complicate the syntax unnecessarily. I like, that the REBOL syntax is minimal. If the feature was allowed, then some programmers might start defining all these functions taking any number of arguments leading to a syntax looking like other languages - like C. I don't feel, that's the heart of REBOL.

If I wanted a function to be able to take any number of arguments, I would use a block. Like this SUM function:
sum: func [b [block!] /local s[
    s: 0
    forall b [s: s + b/1]
>> sum [1 2 8 0]
== 11
I could also define the SUM in a way, so it will take two arguments. Then it could be used like ADD, but second argument could also be a block. An REBOL example taking two arguments is JOIN. Second argument can be a value or a block of values. Makes good sense to me!

One could argue, that the syntax would become even more minimal using a dot as a terminator than specifying a block (start and end character). But it's actual more simple having just one of the possibilities than both, and we already have blocks. (Solution with one possibility has less entropy than solution with two; and therefore less confusion.)
15-Apr-2007 8:38:53
It doesn't seem like a big benefit, unless it opens up possibilities to some breakthrough feature (e.g., rebol-dialect --> rebcode --> scheme --> compiled C).

So, unless there's some major benefit, I'd say forget it.

15-Apr-2007 8:56:07
all[zubzab qab tsurgi squop tonk]

all[(zubzab qab) (tsurgi) (squop tonk)]

all[zubzab qab . tsurgi . squop tonk]

I like it :)

Brian Hawley
15-Apr-2007 9:48:32
I prefer to use (), mainly because it can be easy to miss a period or a comma in your code and have the meaning be lost.

Still, it sounds like something that would be useful for other dialects, so I would like to have a comma! type. In a comment to an earlier blog I suggested that commas be translated to values of the comma! type, and then ignored by the DO dialect evaluator. That would enable its use by other dialects without changing the semantics of DO.

Jeff M
15-Apr-2007 12:32:59
It certainly isn't needed (REBOL hasn't needed it to-date). But there have been a few times that my formatting is a bit off, I've gotten some strange results, and it took me a while to track down where the problem was.

There is - perhaps - another way of looking at the problem. The period (.) syntax isn't to stop argument parsing, but rather to explicitly tell the interpreter, "evaluate what you have now." That may not seem like much of a distinction, but it can be significant, especially if REBOL were to every allow for currying (something the REBOL syntax lends itself to quite well) in the future.

I'm not sure how useful it would be in REBOL otherwise, though. I think it could be nice for debugging (and maybe readability), but it should definitely be optional. I wonder, what effect would it have during infix operation parsing?

15-Apr-2007 13:56:29
Like said above, Rebol syntax is simple and produces highly readable scripts. Periods or commas for argument termination sounds dubious to me. I never ran into trouble neither in that respect. The various option shown in your blog entry should suffise, no?
15-Apr-2007 14:35:20
Another thought on the subject:

In Lisp, if the user wanted a feature not present in the specs (like an argument terminator), said user would write a reader macro. Customization of syntax is easily achieved. Maybe this is the real issue. How can rebol be more flexible syntax-wise?

I say, empower the rebol user to make syntactical decisions of this sort.

Any chance?

Maxim Olivier-Adlhoch
16-Apr-2007 0:37:27
so strange that you should put this online, when I just tought about how the colon could be used as a terminator today and tried to start a discussion on this on altme...

IMHO the only reason for the comma stop would be in the eval and stuff, where calling arguments within a [] or () costs us to call reduce or bind explicitely at each eval, when normally the eval/binding is handled by the interpreter, and would allow a little bit of performance ...

as I think about it more and more (and wrote a bit of dummy code to see how it looked) I find it less and less appealing... REBOL's value passing is already hard to decode on long series handling lines... imagine with terminators on top of it...

I do agree with brian that the colon should be loadable.

IMO (,) should just be treated exactly like dots (.) valid within decimals and words. makes decimal values more international.

it could be used as an explicit space or record terminator for some dialects.

we could load CSV files directly and parse the loaded block knowing where the records are, for example.

16-Apr-2007 2:44:37
I think the usage of parenthesis () and blocks is enough to avoid many programming errors. I'm not sure that an explicit evaluation terminator is the best answer to programmer's errors simply because it's not mandatory.

The only case where I produce difficult-to-find-because-i-forgot-an-argument errors is when I use comments.

mytest: TRUE
a: func [ b c ] [ print ["Values:" b c ] ]
a 4  ; This is comment
either mytest [5] [6]

When I read this code quickly I didn't understand that the 'a function needs a second argument. Maybe because I use other computer languages, I often think that the ";" is a kind of evaluation terminator.

The problem is that the way it's written induce the error.

16-Apr-2007 3:16:17
Some real-life-code from 'layout
     new-face: make any [
        all [parent object? new new] 
        all [parent word? new get-style new] 
    ] any [all [parent block? new new] [parent: 'panel]] 
With terminator:
    new-face: make any [
        all [parent . object? new . new] 
        all [parent .  word? new . get-style new] 
    ] any [all [parent . block? new . new] [parent: 'panel]] 
I like the second better.
16-Apr-2007 3:42:32
dot and comma are already recognise in a decimal! number :
>> type? 1.2
== decimal!
>> type? 1,2
== decimal!

I see no reason to add this feature as other possibilities are already there and more readable IMO.

For the kind of code shown by Volker, I usualy use 2 or 3 spaces to separate the different arguments or newlines, adding a few readability without any counterpart.

new-face: make any [
        all [parent object? new new]      ; no spaces : hum?!
        all [parent  word? new  get-style new]     ; 2 spaces, easier
    ] any [all [parent   block? new   new] [parent: 'panel]]      ; 3 spaces, clearer
16-Apr-2007 4:37:18
I have low (none) experience in language design, but I will try to add my opinion.

Do exists in SAP ABAP programming environment IIRC. I know that, because guys forgot to put dots on many lines initially. But that was needed by parser, as ; is needed in C.

While dots may look good, I am not sure it is, or is not confusing. Some languages might use it (as I said above), but - we have rebcode and we decided to use add.xy, other languages know dots for object access system.view.screen-face (as a path).

I would propose:

- not use (complicate?) default language parser. - as Brian suggests - add terminator! type. But then, reading someone's else source code, we might wonder, what occassional char of word does? - use other char. Paraphrasing Volker:

new-face: make any [
        all [parent : object? new : new] 
        all [parent :  word? new  : get-style new] 
] any [all [parent : block? new : new] [parent: 'panel]] 

Looks quite elegant, similar to | (which would be imo best, if it would not implicate parser's OR). The question is, if someone would not consider it being a wrong assignment. But it quite fits for me - set, get, or get away :-)

16-Apr-2007 8:11:54
Just wonder if there is really someone who is used to write:
>> 1,
== 1.0
>> 1.
== 1.0
For me are these auto corrections useless and would rather see the comma to be a loadable as a special datatype so I could use it in my dialect.

I don't need constructions like: afunc 1 . in Rebol itself as for optional args I use refinements.

But what I would like to know. Would be the terminator terminating only the latest expression? Because if I would see in code something like:

aFunc aFunc a . .
I would not like it at all. I would prefere:
(aFunc (aFunc a))
Maxim Olivier-Adlhoch
16-Apr-2007 9:37:21
didec: darn, I'd forgotten about comma support in decimals!

Oldes: you forget that rebol allows us to load data files... international standards of some/many? countries use the comma for decimal separators and apps which support localization will write out decimal values as such.

16-Apr-2007 10:51:05
Didec, lots of spaces work too. Until the code is loaded and molded back by 'source. then spaces are gone. Or add another smart extension like 'new-line, 'more-than-two-chars? I prefer a terminator. ;) And i use 'source a lot, even if i have the real source. When i a unsure about a function, i put a [source whats-this] just at the point of use. Quick result, and in the right context :)

Pekr, that ":" confused me first, but terminates well. I like it.

Brian Tiffin
16-Apr-2007 13:47:13
I'm a lazy coder.
I'm not such a lazy reader, but like quick grokking.
I'd prefer to read (and write)

afunc 1 none


afunc 1 .

to fill in "missing" arguments.

In the afunc with early termination you'd have to explicitly test for unset? b values to avoid an error throw during simple debug (probe).

It took a while, but I've gotten quite used to the power of the arity scanning. It let's you do all the funky

any [...] all [...]

shortcutting wherever and whenever. And going forthy with + 2 3

(but I'll admit that

* 2 3 * 4 5

confused the crap out of me at first)

In short. I'd say pick a placeholder instead of early termination. Less muck, easier grok.

Gregg Irwin
16-Apr-2007 15:27:31
I don't think we need it. For Volker's example, which is a good one, I just add extra spaces. e.g.

new-face: make any [ all [parent object? new new] all [parent word? new get-style new] vid-face ] any [all [parent block? new new] [parent: 'panel]]

new-face: make any [ all [parent . object? new . new] all [parent . word? new . get-style new] vid-face ] any [all [parent . block? new . new] [parent: 'panel]]

new-face: make any [ all [parent object? new new] all [parent word? new get-style new] vid-face ] any [all [parent block? new new] [parent: 'panel]]

Rob Lancaster
16-Apr-2007 16:47:49
Well, If you were typing stuff into a CLI, then being able to throw down a . at the end of the line, would be far preferable to using braces... If you forgot to add them at the start of what ever you were typing...

But then I guess that should be part of the command line Dialect parsing thingy that one is using?

Would this terminator make more sense if you brought a different set of refinements to arguements?

  print-name "Johny Rotten" /colour "Red" /style "Shouty" .

But then it could start to look like (cough) powersh*ll..

16-Apr-2007 18:28:01
Brian, if you want to just write:

afunc 1 .

instead of:

afunc 1 none You can use:

.: none
The comma is discriminated as it's not loadable as a word, but dot can be.

And Maxim, I really don't know what has writing 1. or 1, to do with international standards. I understand that someone is used to write 1.0 and someone else 1,0 but is there really someone who is used to write 1, * 2.? Is this really good for something? That you save one byte? and one key hit?

Maxim Olivier-Adlhoch
16-Apr-2007 22:33:22
who is talking about code you write, I am talking about loading data files. I've encountered both forms of decimals in the past in ascii data files.

so wether a single file has both is irrelevent, we just have to be sure we support both.

17-Apr-2007 5:32
.: none

That's clever, Oldes! But it is not quite the same as a termination symbol. If afunc took four arguments, Brian would have to write

afunc 1 . . .

Brian Tiffin
17-Apr-2007 11:09:58
Ahh, but I prefer to read

afunc 1 none

and I use

cd: :change-dir
.: %.
..: %..

in my %user.r.

So I can type cd ../../svn commands in the console. Remember, I'm a lazy coder. It's the reading I want to make as fast and unambiguous as possible. :)

Al c
17-Apr-2007 21:14:24
I see this feature more useful for the console than for coding.

But for the console I would prefer the newline char as terminator! :)

Perhaps Is a dialect for the console the way?

18-Apr-2007 9:39:30
Sunanda.. i know that it's not used like terminator. I just wanted to show, that I can use dot as a normal word, but cannot use comma. That's all. And I don't think I need to use optional funcs args without the refinements as is normal in Rebol. But understand, that someone else may need it. By the way... Brian, that's claver with the dots as path shortcuts, I was already using cd: :change-dir but now I will use your addition as well:)
19-Apr-2007 4:29:49
Once i tried this. Maybe if it would be native, i would use it :) . '. simply returns its argument. then this works:

all[1 . 2]


.: func [arg] [:arg] ;TODO should deal with unset etc..

Note: native would also be nice for debug-statements, which usually have 1 argument.

debug: :. ;and now logging is switched off

19-Apr-2007 14:02:37

Punctuations kill the programmer... ...not to speak the debugger

...replace the punctuations with soneting more linguistic.. like.. 'dot 'comma or 'end 'fin 'stop

Brian Hawley
19-Apr-2007 21:38:01
Brian T., I like the . and .. file trick too, and will definitely be using it :)
20-Apr-2007 5:09:30
IMO source code would look to much Perlish for us :-).
21-Apr-2007 17:02:56
I second Henrik's stop word. And Robert has a point. It may be very natural for well schooled Reboler's to employ such a device but I believe that for simplicity sake and for future readability by the non-Rebol guru, it is good to stick to words, the speed and ease of using a "." notwithstanding.

IMHO, part of Rebol's allure is that it is easy to understand. You know, just a few simple words and voilá, you're sending Luke Skywalker an email (which of course he would have read a long time ago in a...)

Thanks for the examples, guys. You rock.

Arie van Wingerden
22-Apr-2007 15:19:38
I prefer to use () and blocks where needed. Extra syntax (like e.g. these periods) is overkill and will make the code less clear (especially for noobs), because the dots will only appear in specific situations (they wouldn't be used with every function call).
24-Apr-2007 2:57:01
I would rather continue without terminators. If you decide to go with them would prefer a word dots are small and I sometimes forget my cheaters.

Post a Comment:

You can post a comment here. Keep it on-topic.


Blog id:



 Note: HTML tags allowed for: b i u li ol ul font span div a p br pre tt blockquote

This is a technical blog related to the above topic. We reserve the right to remove comments that are off-topic, irrelevant links, advertisements, spams, personal attacks, politics, religion, etc.

Updated 27-May-2024 - Edit - Copyright REBOL Technologies -