Hi daniel
I send it into the mailing list too becuase this is important
From a language design perspective
#() is necessary because it is compiled statically and cannot not be simulated by other construct. Storing #() in Stack frame is not really goo but this is an implementation aspect.
#{} is not necessary because this is shortcut macro-expansion for Array new add: ....
So why having only this one. There is two ways: or you have a way to describe macro-expansion like in Scheme where you can define any macro in a clear way (you know the semantic of the stuff
or we remove it because why not having {{}} for Set new add: {#[]} for OrderedCollection new....Because I use more OrderedCollection than array
Removing would simply the parser, compiler, Object simpler the printer printer the VM, the bytes code emitter, then Squeak would be a bit more standard but this is not the most important point. Why can I send the message caseOf: to ___any Object___ berk!!!!
I'm pretty sure that I can destroy the semantics prevservation of certain refactoring (I did it for ObjectStudio RB because OS has this &(*&*&( construct too). The parser of Rb in Squeak has to e more complex than the one of VW because of the expressions inside {}....
And it would avoid to have people writing, (I saw that in indsutrial code people wrote __huge__
{ {,.n,mnm, } {knlkj lk jjkl with block everywhere} {,.n,mnm, } {knlkj lk jjkl with block everywhere} {,.n,mnm, } {knlkj lk jjkl with block everywhere} {,.n,mnm, } {knlkj lk jjkl with block everywhere} {,.n,mnm, } {knlkj lk jjkl with block everywhere} }
So I hope that I convince you. I will try to came up with a change ste that REMOVE this anthrax from Squeak!!!
Stef
Stef:
But...... I use it all the time. It's a neat idea. Here is code I found by searching all source for #{.
EToyIncommingMessages class>>allTypes
^MessageTypes ifNil: [ MessageTypes _ { self typeKeyboardChat. self typeMorph. self typeFridge. self typeStatusRequest. self typeStatusReply. self typeSeeDesktop. self typeAudioChat. self typeAudioChatContinuous. self typeMultiChat. } ]
HeadMorph>>addSpikyHair | hair | hair _ PolygonMorph vertices: {83@3. 81@30. 91@27. 111@23. 97@32. 112@37. 99@45. 114@52. 95@53. 55@43. 10@50. 1@40. 14@40. 8@26. 24@37. 15@11. 29@29. 30@16. 36@30. 41@6. 49@31. 54@8. 61@32. 64@1. 70@27}
Next is a fragment of a demo. The names Babble, Donut and Marble are humorous, but descriptive.
d := BabbleDonutMorph new largeDonut; name: '- Commons Area -'. d addAllMarbles: { (BabbleMarbleMorph new mediumMarble name: 'Wendy'). (BabbleMarbleMorph new mediumMarble name: 'Dave and Archie at home'). (BabbleMarbleMorph new mediumMarble name: 'Tom in Minneapolis'). (BabbleMarbleMorph new mediumMarble name: 'Mark'). (BabbleMarbleMorph new mediumMarble name: 'Big Screen'). (BabbleMarbleMorph new mediumMarble name: 'John in the Lab') } shuffled.
These are just a few examples I picked to show 'interesting' uses of { and }. I found 794 methods in my image that contained at least one ${. A few were commented out C code. Most were from the array constructor. It's used widely and the result of using it makes the code much more readable than 'Array with:'.
The construct is useful and widely used. If it has definitional and theoretical problems, then certainly look at how to fix those; but let's not discard a useful construct.
At 8:49 +0200 9/30/01, ducasse stephane wrote:
Hi daniel
I send it into the mailing list too becuase this is important
From a language design perspective
#() is necessary because it is compiled statically and cannot not be simulated by other construct. Storing #() in Stack frame is not really goo but this is an implementation aspect.
I don't think this is true at all. #() holds symbols, strings, characters numbers, and in some Smalltalk systems it holds true and false. There is nothing in a #() that you can't write as a literal elsewhere, so:
#( abc 'abc' 4 3.4 $r )
can be written as:
(Array with: #abc with: 'abc'), (Array with: 4 with: 3.4 with: $r)
#() is a great convenience, but it is not absolutely necessary.
#{} is not necessary because this is shortcut macro-expansion for Array new add: ....
So why having only this one. There is two ways: or you have a way to describe macro-expansion like in Scheme where you can define any macro in a clear way (you know the semantic of the stuff
or we remove it because why not having {{}} for Set new add:
This already has a definition: an empty array in an array, like: #(#()).
{#[]} for OrderedCollection new....Because I use more OrderedCollection than array
#[] isn't used in Squeak, but some Smalltalk systems (and maybe the standard) use it as a way of writing ByteArray literals: #[ 0 255 76 98 4 67 2 ]. We should carefully decide if we want to differ from others in syntax. (Actually, 'we' already have; for some odd reason '#[' is a symbol! I would have expected to have to write #'[' to get a symbol with a special character.)
I use more OrderedCollection's too, but it was interesting to note that after looking at a couple of hundred uses of {} I don't recall seeing even one message send to convert the array to something else. I think that OCs are widely used when code is building an indexed collection, but rare when the collection is built ahead of time by a literal array or array constructor.
... SNIP ...
Dave
Hi David
At least you did not insult me so this is a good point. (But I was expecting so from you ;))
I really like how people react to simple design language questions. May be I'm abrupt but the discussion worth the bandwidth ;)
The construct is useful and widely used.
Widely in which code???? Where? more than OrderedCollection?
I developped a lot of stuff in VW and never found the need to have {}.
If it has definitional and theoretical problems, then certainly look at how to fix those; but let's not discard a useful construct.
But I wish I could send you the kind of code you can write with {} believe me this is really ugly. So some people will say that this is the case with everything and the discussion will end.
I thought that Smalltalk was looking for simplicity. So or we should have a way to describe macro-expansion or remove them!
***The next paragraph is provocative so read before replying ;)***
Having private methods and attributes is useful too. Sometimes I would like to do real design in Smalltalk. Having operators is useful too, I would like to have operators too because I prefer to type 2 + 3 * 6 than 2 + (3 * 6) and because this is MATH and MATH are right!
I hope you see my point.
I like the simplicity of Smalltalk and I'm ready to pay the price to use convention for expressing private, dealing with operator by hand.... I like simplicity but I do not like this #{} because this is against the simplicity and ad-hoc!!!
When I checked me code I can tell you that I have much more ordered collection than array still there is no construct. So I would really like to have one too!!!!!!!! may be {{}} could be good.
So the real question is should simplicity be conversed or not. Is it worth to have caseOf: in Object and all these BraceNode in the compiler, why do we need that?
I was wondering if { could not be like @
we could write Array { 1@1; { 1@2 I'm not sure that this uglier than #{ 1@1 . 1@2}
because at least this is a message send without special rule
At 8:49 +0200 9/30/01, ducasse stephane wrote:
Hi daniel
I send it into the mailing list too becuase this is important
From a language design perspective
#() is necessary because it is compiled statically and cannot not be simulated by other construct. Storing #() in Stack frame is not really goo but this is an implementation aspect.
I don't think this is true at all. #() holds symbols, strings, characters numbers, and in some Smalltalk systems it holds true and false. There is nothing in a #() that you can't write as a literal elsewhere, so:
#( abc 'abc' 4 3.4 $r )
can be written as:
(Array with: #abc with: 'abc'), (Array with: 4 with: 3.4 with: $r)
#() is a great convenience, but it is not absolutely necessary.
#{} is not necessary because this is shortcut macro-expansion for Array new add: ....
So why having only this one. There is two ways: or you have a way to describe macro-expansion like in Scheme where you can define any macro in a clear way (you know the semantic of the stuff
or we remove it because why not having {{}} for Set new add:
This already has a definition: an empty array in an array, like: #(#()).
{#[]} for OrderedCollection new....Because I use more OrderedCollection than array
#[] isn't used in Squeak, but some Smalltalk systems (and maybe the standard) use it as a way of writing ByteArray literals: #[ 0 255 76 98 4 67 2 ]. We should carefully decide if we want to differ from others in syntax. (Actually, 'we' already have; for some odd reason '#[' is a symbol! I would have expected to have to write #'[' to get a symbol with a special character.)
I was not serious dave. I do not want {#[]}
#[] is enough for me. I never use it!
I use more OrderedCollection's too, but it was interesting to note that after looking at a couple of hundred uses of {} I don't recall seeing even one message send to convert the array to something else. I think that OCs are widely used when code is building an indexed collection, but rare when the collection is built ahead of time by a literal array or array constructor.
I agree with that. I tend to start with OC and then convert them as much as possible into Array.
Dave
Stephane,
First of all, if you're making a pretty polemic proposal (I think not only I found your "examples" of {{}} etc. to be polemic and your last message just dumped more oil on the fire) then you shouldn't be surprised to get responses in a similar tone. Having said that, let me point out a few issues that you seem to be overlooking (note that I'm *not* trying to be polemic here, all of the examples I'm giving you are true to the point):
[Re: Difference between @ and {}]
There is a big different @ is a message not a parsed construct with specific rules!!!!!
Sorry, but that's wrong. @ (and all binary operators) are just that: Parsed constructs with specific rules. From a point of purety we don't need them. We could just write: (1 add: 2) times: (3 add: 4) and get exactly the same result that we get today from (1+2) * (3+4). So fundamentally there is no difference whatsoever between @ and {} - both are parsed constructs and both have specific rules.
[Re: Use of {}]
The construct is useful and widely used.
Widely in which code???? Where? more than OrderedCollection?
Counting all the references to OC comes up to 720 (on my system; your milage may vary) - and very many of them are used in a form that would not be equivalent to {}. Whereas the cumulative references to {} (note that you have to add all of the #braceWith: variants as well as #braceStream:) come out to 692. So the answer to "more than OrderedCollection?" is, yes, for constructing an immediate collection of Objects, {} is in fact more used than OrderedCollection. Again, I'm not trying to be polemic here - these are facts that you can count for yourself.
[Re: Looking for simplicity]
I thought that Smalltalk was looking for simplicity.
Simplicity and purety are two different things. "Simple" can mean different things to different people. Originally, Smalltalk was intended to be a language for kids (but, alas!, how far away has it gotten) and I don't think that kids who learn in school that 4+5*6 equals 34 will find it simple that Smalltalk evaluates this to 54. They might find it pure if they can comprehend the reasoning behind it ... but simple?!
[Re: The price we pay]
I like the simplicity of Smalltalk and I'm ready to pay the price to use convention for expressing private, dealing with operator by hand....
I think that is the real point. What price are we willing to pay. As I've said above (and as has been pointed out by other posters) we could theoretically live without a lot of constructs, including binary operators, $ for character creation, #() for literal array creation, etc. But we're simply unwilling to pay that price because we've got used to the convenience these expressions give us. If that is so, then your message comes down to two problematic points
#1: The ability to write horrible constructs That's certainly an issue but I don't think it's as bad as you're making it. Briefly glancing over some of the 672 methods that use brace construction I couldn't find any that used it in a truly ugly way. Which means that most people using the construct use it in the way it should be used. Ugly code can be written with many syntactical constructs, including, for instance: (a := b > 5 ifTrue:["doSomeThing"]) ifNotNil:[ ... ]. I find the above at least as ugly as some of your examples (note that the hidden ifFalse: branch will in fact evaluate to nil and the assignment in the expression doesn't help readibility either).
#2: Not being ANSI compatible Again, certainly an issue but for people who wish to write stuff that ports easily over to other dialects, they're not required to use this construct. As you have pointed out, there are alternatives and if one wishes to write easily portable code then he or she just has to pay the price. If not ... why pay it?
Cheers, - Andreas
PS. One last note which might be considered a bit polemic so it comes only after the actual message:
Having operators is useful too, I would like to have operators too because I prefer to type 2 + 3 * 6 than 2 + (3 * 6) and because this is MATH and MATH are right!
I hope you see my point.
If your point is that we should not have appropriate operator precedences, then I don't see it. I find absolutely nothing wrong with them. There are plenty of language (Prolog, for example) dealing with operator precedence pretty well and at the same time not restricting people to use only built-in operators. So actually I agree - I want operator precedences too! ;-)
Andreas Raab wrote:
Having operators is useful too, I would like to have operators too because I prefer to type 2 + 3 * 6 than 2 + (3 * 6) and because this is MATH and MATH are right!
I hope you see my point.
If your point is that we should not have appropriate operator precedences, then I don't see it. I find absolutely nothing wrong with them. There are plenty of language (Prolog, for example) dealing with operator precedence pretty well and at the same time not restricting people to use only built-in operators. So actually I agree - I want operator precedences too! ;-)
I think we should be careful on this slippery slope...as you point out, there is a delicate balance between simplicity and purity. Many languages have been ruined by adding constructs that were meant to make things more convenient but sacrificed consistency. I think this was Stephane's point actually. These constructs usually make a language more convenient for those with a lot of experience in the language, but much more difficult for people new to the language. If you need proof of this, just look at the recent thread titled "Storing and Retrieving Points."
I'm not arguing against using mathematical precedence, just that the idea be carefully considered. Also, there are many mathematical expressions that cannot be rendered in plain text. Why not augment Squeak with the complete language of mathematics instead? Let's allow a mathematical expression to be constructed using a full graphical representation and then be dropped into a method.
- Stephen
I think we should be careful on this slippery slope...as you point out, there is a delicate balance between simplicity and purity. Many languages have been ruined by adding constructs that were meant to make things more convenient but sacrificed consistency. I think this was Stephane's point actually. These constructs usually make a language more convenient for those with a lot of experience in the language, but much more difficult for people new to the language. If you need proof of this, just look at the recent thread titled "Storing and Retrieving Points."
This is where the discussion should be!
I'd actually rather get rid of #() than {}. #() is the confusing one, and it's really only there for speed. Yet, the compiler could easily check whether a {} instance can be converted to #() internally....
Admittedly, we could even gid rid of both of them, and not be too bad off. They sure are convenient sometimes, though, especially for hacking around in a workspace.
By the way, to maintain the ability to interchange with ANSI, we can take advantage of Stephan's note and expand the construct on fileout as:
(Array new: 10) at: 1 put: foo; at: 2 put: bar; ... yourself
With a moderate effort, this construct can even be changed back when code is read back in.
-Lex
I think we should be careful on this slippery slope...as you point out, there is a delicate balance between simplicity and purity. Many languages have been ruined by adding constructs that were meant to make things more convenient but sacrificed consistency. I think this was Stephane's point actually. These constructs usually make a language more convenient for those with a lot of experience in the language, but much more difficult for people new to the language. If you need proof of this, just look at the recent thread titled "Storing and Retrieving Points."
This was my point even if I expressed so badly. Sorry for that. I do not knwo who wrote that but YES YES YES. This is what I wanted to say.
This is where the discussion should be!
I'd actually rather get rid of #() than {}. #() is the confusing one, and it's really only there for speed. Yet, the compiler could easily check whether a {} instance can be converted to #() internally....
As daniel mentioned it this is indeed an interesting alternative. At the end we would have only one construct.
Admittedly, we could even gid rid of both of them, and not be too bad off. They sure are convenient sometimes, though, especially for hacking around in a workspace.
By the way, to maintain the ability to interchange with ANSI, we can take advantage of Stephan's note and expand the construct on fileout as:
(Array new: 10) at: 1 put: foo; at: 2 put: bar; ... yourself With a moderate effort, this construct can even be changed back when code is read back in.
-Lex
On Mon, 1 Oct 2001, Andreas Raab wrote:
[snip]
[Re: Difference between @ and {}]
There is a big different @ is a message not a parsed construct with specific rules!!!!!
Sorry, but that's wrong. @ (and all binary operators)
Just to be tidy (I *hope* I'm being tidy), I think the parenthetical comment is part of the point. binary messages (i.e., a message *form* which can take *only* one argument, no more, no less) are reasonably generic. And even reasonable extensible...it wouldn't be *that* hard to add prolog style op() for binary messages (oh hell, let's call them operators). Indeed, we could unify more syntax under that rubric (e.g., :=) with some finessing.
are just that: Parsed constructs with specific rules. From a point of purety we don't need them. We could just write: (1 add: 2) times: (3 add: 4) and get exactly the same result that we get today from (1+2) * (3+4). So fundamentally there is no difference whatsoever between @ and {} - both are parsed constructs and both have specific rules.
I take it that the intended difference in the examples is that #@ is the exemplar of a piece of more general syntax (binary messages, which themselves are instances of messages in general), thus could be replaced with other examples of that syntax (e.g., #+). {} on the other hand is relatively uniqure and definitely special case...in the way that #() is special case, and, indeed, ^ and :=.
[snip]
Simplicity and purety are two different things. "Simple" can mean different things to different people. Originally, Smalltalk was intended to be a language for kids (but, alas!, how far away has it gotten) and I don't think that kids who learn in school that 4+5*6 equals 34 will find it simple that Smalltalk evaluates this to 54.
But those reading it aloud might, or those entering into a simple calculator. It's very nice to be able to accumulate an intermediate result and forget all that came before.Precedence is rarely all *that* simple :), by any measure (except, maybe, character count when you eliminate the grouping parens). I would be very interested to know if there were studies about precedence error...many programming style guides encourage adding parens to indicate precedence (or brekaing complext expressions into subparts).
They might find it pure if they can comprehend the reasoning behind it ... but simple?!
Unexpected, yes. Hard to get used to...maybe. But why wouldn't they find it *simple*? I mean, right to left vs. all over the place....that seems like a no brainer. No, it might be *too* simple for certain purposes...perhaps even by introducing more complexity elsewhere.
[snip]
There are a lot of issues here, of course. E.g., other smalltalks are using {} for a variety of things; there are packages (the prolog and lisp interpreters) which use {} as an "escaping" mechanism...and whether having a certain special form, all by itself, is worth it.
Personally, I tend not to use it since I rarely think to and, since I don't use it, I find it a bit annoying because I don't remember exactly what it does and how.
However, I *do* think that it deserves a bit of special care since it's one of the relatively few grouping punctuation. We already use () and [] (and, indeed, overload ()). So perhaps there's a more general syntax use of {} that we might want to use it for?Embedding sublangauges, maybe, or just for macros. Prefixed with a #, it could be used for extended, user defined, literals. (e.g., #{URL:http://www.foo.org/} could be equivalent to 'http://www.foo.org' asUrl...ok, that's not much of a win :), so #{http://www.foo.org.%7D).
Hmm. Actually, maybe just extending #() is the right thing, like lisp...#S(...) or #I(2+3*5) (an infix package).
Finally, perhaps a Preferance...browseWithoutBraceConstruct? :)
Cheers, Bijan Parsia.
Hi andreas
I was polemic, you are right. I wanted to get people react. I wanted to know the point of view of other people. And to get reaction I have to push hard. So thanks for your remarks they made me thinking.
I will try to get these discussions on a wiki because I like them.
So fundamentally there is no difference whatsoever between @ and {} - both are parsed constructs and both have specific rules.
You are right again ;) I said it in the wrong way. * is parsed as a binary but does not have a specific parseNode. I started to wrote a pretty printer and was really wondering why we have {} Then I checked the code and found that I could send caseOf: to any object ;( and I was really trying to see the benefit of this nice construct
Simplicity and purety are two different things. "Simple" can mean different things to different people. Originally, Smalltalk was intended to be a language for kids (but, alas!, how far away has it gotten) and I don't think that kids who learn in school that 4+5*6 equals 34 will find it simple that Smalltalk evaluates this to 54. They might find it pure if they can comprehend the reasoning behind it ... but simple?!
Right I meant purity. So from a language design point of view what is the limit for having or not a construct. I was really thinking that only := and ^ are the ones necessary. Am I wrong?
Then the question stays the same why only {}? This is the same in VA and VW why #[] for byte. But in VW community there is no freedom, you buy a stuff and you accept it.
I think that is the real point. What price are we willing to pay. As I've said above (and as has been pointed out by other posters) we could theoretically live without a lot of constructs, including binary operators, $ for character creation, #() for literal array creation, etc. But we're simply unwilling to pay that price because we've got used to the convenience these expressions give us. If that is so, then your message comes down to two problematic points
I'm not sure in fact.
Is there a way to express literal Array differently (by sending messages) than #()?
With purity in mind should not be a construct something that cannot be created or having the same runtime behavior.
Because I was wondering when I write $a and Character with: 'a' this is different from the compiler point of view? At least in VW the second one is evaluated at every method invocation while the first one is stored into the method stack frame.
I would like to know if I'm wrong: if we consider the creation of object #() and Array new are different expressions (not equivalent) because one always create objects will the other not. {} and Array new are the same Character with: 'w' and $w are different Is it not the way to distinguish what can be created the same way from things that cannot?
#1: The ability to write horrible constructs That's certainly an issue but I don't think it's as bad as you're making it. Briefly glancing over some of the 672 methods that use brace construction I couldn't find any that used it in a truly ugly way. Which means that most people using the construct use it in the way it should be used. Ugly code can be written with many syntactical constructs, including, for instance: (a := b > 5 ifTrue:["doSomeThing"]) ifNotNil:[ ... ].
We can write bad stuff with anything. I was more into trying to getting rid of this ad-hoc, single and specific macro-expansion. I was wondering why during the five years I program in Smalltalk I did not need it, nor the people I know working in VW.
I find the above at least as ugly as some of your examples (note that the hidden ifFalse: branch will in fact evaluate to nil and the assignment in the expression doesn't help readibility either).
Oh sure I'm not saying that we cannot write ugly code with ifTrue. I found in C++ application a single method of 5000 (yes 4 zeros) named create button, or a complete parser 600 lines only made with if statement. In Smalltalk I think that the fact that the lenght of a method is limited at least in VW is a good thing. I also saw really crazy method in objectstudio applications based on {{}{}{}}
#2: Not being ANSI compatible Again, certainly an issue but for people who wish to write stuff that ports easily over to other dialects, they're not required to use this construct. As you have pointed out, there are alternatives and if one wishes to write easily portable code then he or she just has to pay the price. If not ... why pay it?
Been compatible could be a concern but I do not consider that deviating is a problem when this is needed.
PS. One last note which might be considered a bit polemic so it comes only after the actual message:
Having operators is useful too, I would like to have operators too because I prefer to type 2 + 3 * 6 than 2 + (3 * 6) and because this is MATH and MATH are right!
I hope you see my point.
If your point is that we should not have appropriate operator precedences, then I don't see it. I find absolutely nothing wrong with them. There are plenty of language (Prolog, for example) dealing with operator precedence pretty well and at the same time not restricting people to use only built-in operators. So actually I agree - I want operator precedences too! ;-)
I respect C++ because you can redefine operator and even -> if I'm not wrong, the goal was to allow people to express what they want, I respect and I'm ready to pay the price of Smalltalk on the autel of purity (where something I would like to have operators, private...). After solution in Java are in the middle of nowhere and are stupid.
My point was just to illustrate that I can deal with no operator in Smalltalk if this is for simplicity and/or purity. So as soon as I program in Smalltalk I accept this fact because this design makes life simpler for the compiler, the programmer (sometimes not the designer)...
Thanks for the time you send arguying with me. I think that I know now why I do not like {} ;)
squeak-dev@lists.squeakfoundation.org