Improving The Smalltalk Design

Moved here from SmalltalkLanguage by way of SmallTalkDiscussion?, wherein someone took to butchering it up for spare parts. Or maybe they were potting up the seedlings so that each had it's own space to grow? Repotting is traumatic to plants, which is why you don't do it until you're sure they're healthy.

Why doesn't Smalltalk have partial evaluation of blocks?

I'm not sure what you mean. If you can supply an example demonstrating what you'd like, it may already be there.

([:a :b | a + b] value: 20) evaluates to [:b | 20 + b]

Ah, so the question appears to be: why can't you do CurryingSchonfinkelling of blocks? Is this a different question from why aren't blocks full featured lambdas? PeterDeutsch revised the Smalltalk-80 implementation of blocks to be full closures with very little effect on programming style.

Why does Smalltalk use the ugly 'value: anObject' syntax to evaluate a block (see SyntaxFollowsSemantics)?

Ugly or not, it uses the #value: selector to invoke evaluation of a block in order to avoid creating special syntax for blocks. The #value: selector is used, by convention, throughout the system when evaluation with one argument is requested (not just for blocks). By the way, if two arguments are needed, the convention is #value:value:.

I want special syntax for blocks! There already is special syntax for blocks; the square brackets. Why don't Smalltalk users create blocks using some Block new process? Because the special syntax for blocks is a lot more beautiful, understandable and undaunting than (lambda (x) (blah blah x)).

The syntax I want is

([:a :b | a + b] : 20 : 10) => 30

where parentheses are the syntax denoting evaluation. Why do I want just ':'? Because blocks are anonymous methods, so I want anonymous selectors to go along with them! I also want to be able to write

variable1 := [:a | a + 10]. ^(variable1 : 20)

When the parentheses are missing, they are implied. Just like in Self, self can be implied. I don't like this implied stuff but can accept it for backwards compatibility.

The purpose of the square brackets is to tell the compiler to bundle up and compile (but not evaluate) the enclosed code. One of the differentiating aspects of the various environments is how they handle binding to locals and the stack frame (at block creation time). As you see, the square braces define the extent of the body. The #value: (or #value:value: for two arguments) syntax connects the block to the rest of the language/environment. Remember that the compiler uses the square block to create an instance of class Block or one of its descendents. The #value: messages are "regular" methods defined on that class -- you can certainly create your own. See class True and False for various ways to hide the #value messages from users if you like.

But you don't need special syntax. Lisps do fine with (lambda (x) ()). If the compiler wants to cheat then I'm all for it, so long as it's handled transparently, without needing me to give hints along the way. It isn't the programmer's job to baby the compiler anymore than it's the user's job to baby their programs. If (compiler) programmers understood this, we'd all have better software.

Why does Smalltalk have syntax at all?

What are you really asking here?

Why not define Smalltalk in terms of parse trees and libraries, then let the authoring environments put in as much or as little syntax as the user wants. If someone wants color code highlighting (syntax) then let them have it. If a newcomer from the C world is freaked out by the lack of syntax, let them have lots of braces and periods. And let me be able to read his code without having to deal with any of his ugly syntax.

I think that's totally possible, much or perhaps even most of the object structure is already there. The various parse trees (along with the compiler) are already in the environment (along with source), as are the runtime structures, such as frames, methods, bytecodes, processes, and so on. There is surely nothing sacrosanct about the particular syntactic decisions made by the original language designers.

Can you give us some examples of syntax vs. non-syntax statements and what advantages there might be? I am interested in this. Is this strictly for expression of the programmig concepts, or is it deeper, about coding design concepts in a differnet way?

I think the concept is that there are two distinct concepts, both of which go by the term 'Programming Language'. One is the syntactic form; what is and isn't a valid textual construct, what can be captured by a formal specification of the text. The other is the unique datastructures and processes of the language; the unique aspects of the language which make it identifiable outside of its typical textual source code.

Think of the english language. Think of written english. The written english is not english (for a suitable definition of 'english'). It's a written representation of english. Spoken english is likewise not english. It's a spoken representation. What we're getting at is the essence of english, which wouldn't change even if the spoken and written forms did. The commonality between the written word 'the' and the spoken word 'the'. Effectively, the separation of the thing from any given interface to it.

--WilliamUnderwood

See also SourceCodeInDatabase

---

Smalltalk would be more self consistent if it required the implicit keywords in a blocks prototype to be spelled out. Imagine this:

  sum := aCollection inject: 0 into: 
     [value: sum value: each | sum + each] 

The block invocation methods, value:, value:value:, etc., are just normal method selectors that can be implemented by other objects. For example, a favorite hack of mine is to define value:value; for Symbols this way:

  value: a value: b 
     ^ a perform: self with: b 

This allows the inject above to be written without creating any blocks what so ever:

  sum := aCollection inject: 0 into: #+ 

This works because the inject:into: uses ordinary messaging to evaluate its second argument.

Why don't ST environments EmbedReferencesInSourceCode then represent these references with some special syntax, if applicable, instead of parsing from a limited set of built-in literals? Why separate code-time from run-time? Why have literal representations of objects always create new objects instead of just sticking the actual object (not a literal representation) directly into your code?

If you started with Smalltalk or Self, and you made the perfect language, what would it look like?

I have no clue what a "perfect language" is. I'd like to see some additional semantics, and I'm fine with the syntax of Lisp, Smalltalk, or perhaps Python.

See at the bottom of QuestForThePerfectLanguage


Smalltalk should have AutomaticLocking, just like it has Automatic GarbageCollection.

I'm already sick and tired of dealing with locks, and I've never had to deal with them yet.


EditText of this page (last edited January 2, 2004) or FindPage with title or text search