
If-statements in Smalltalk (2008) - ColinWright
http://pozorvlak.livejournal.com/94558.html
======
dws
The explanation is almost correct, but misses a tiny, but interesting detail.
Subclasses of Boolean do implement #ifTrue: and #ifFalse:, wich each take a
block (a no-argument function) as an argument. But they also implement
#ifTrue:ifFalse:, which takes two blocks as arguments. In

    
    
        a < b:
            ifTrue: [...]
            ifFalse: [...]
    

a single message (#ifTrue:ifFalse:) is sent to the boolean that results from
evaluating 'a < b'. A true, being the singleton instance of the True subclass
of Boolean, evaluations the first argument and ignores the second. False has a
singleton instance, false, that does the opposite.

Coming from Pascal and C, seeing that IF/ELSE could be implement without
special syntax was a real mind warper.

~~~
i_feel_great
There should be no colon after the predicate (i.e., after the "b").

------
vbit
Anyone interested in playing around with Smalltalk can use
[https://pharo.org](https://pharo.org) \- I recently tried it and was pretty
amazed with the quality of documentation available. It is quite a different
experience working in an interactive live environment.

~~~
wry_discontent
I briefly looked into it, but I can't seem to figure out what to make with it.
It looked like you couldn't write an application with any portability, and any
user would basically have to run a smalltalk vm to use your application. Am I
mistaken?

~~~
pozorvlak
This is my understanding, yes -
[http://wiki.c2.com/?ImageBasedLanguage](http://wiki.c2.com/?ImageBasedLanguage)
. Some Lisp systems and the Factor language also work like this (though Factor
does a lot of work to ensure that the contents of your image matches the code
on disk). I believe it's possible to strip down your image for deployment so
it only includes code required by your application.

Then again, we live in the era of Docker, in which it's commonplace to ship an
entire Linux filesystem along with your web app. So shipping a Smalltalk VM
(2.6MB for Pharo 5.0) shouldn't be too much of a stretch.

------
vbit
This applies to loops as well. Numbers are objects that accept the
`timesRepeat:` message:

    
    
        10 timesRepeat: [ n := n*2 ].
    

Not only that, you can send messages to blocks, to implement loops.

    
    
        [ n < 10 ] whileTrue: [ n := n + 1 ]

~~~
vidarh
Compare to Ruby:

    
    
        10.times { n = n * 2 }
    

The latter isn't possible "out of the box", but easy enough to implement:

    
    
        class Proc
            def whileTrue; yield while self.call; end
        end
    
        # And use:
        n = 1
        ->{ n < 10 }.whileTrue { n = n + 1 } 
    
        puts n
    

Ruby syntax does get in the way of some of the more succint ways of defining
control structures in Smalltalk, but the above shows some of the Smalltalk
heritage of Ruby quite well, I think (though, while "10.times" is fairly
idiomatic Ruby, implementing constructs like the one below certainly is not).

------
singingfish
if statements considered harmful:
[https://blog.deprogramandis.co.uk/2013/03/20/if-
statements-c...](https://blog.deprogramandis.co.uk/2013/03/20/if-statements-
considered-harmful-or-gotos-evil-twin-or-how-to-achieve-coding-happiness-
using-null-objects/)

~~~
NegativeLatency
That title is very clickbaity, but the article was quite good.

------
pg314
Since if-statements are built out of blocks and message sending, you can
easily do some cool things. One of them is building up an abstract syntax tree
(AST) of an expression without parsing that expression.

E.g. suppose you want to build up an AST of the statement

    
    
      (x < 0) ifTrue:[-x] ifFalse:[x]
    

Instead of starting with an x of type Number, you would start with an object
of type ASTVariable, that responds to the message < by creating and returning
an object ASTLessThan instead of the Boolean True or False. When that object
is sent the ifTrue:ifFalse: message it evaluates both branches to create the
ASTs for both branches and then creates an ASTIfStatement.

As an sexp:

    
    
      (ASTIfStatement
        :condition (ASTLessThan #1=(ASTVariable :name x) (ASTConstant :value 0))
        :consequent (ASTUnaryMinus #1#)
        :alternative #1#)
    
    

I've seen it used in a number of embedded languages in Smalltalk, such as SQL.

~~~
taejo
This technique is limited by the fact that it only works if all the messages
are sent to x, rather than x being sent some message.

~~~
pg314
You mean "rather than x being sent _to_ some message"? E.g. 0 > x wouldn't
work, because the message #> is sent to 0 with x as an argument? In a case
like that you can still make it work by exploiting the fact that arithmetic
and comparison operators implement double dispatch. The implementation of >
for an Integer would send a message to x:

    
    
      Integer::> aNumber
        ^x adaptToInteger: self andCompare: #<
    

Even if x is passed as an argument, to interact with it at some point somebody
has to send a message to it. I agree that it can become unwieldy to intercept
all possible messages, but for a well-defined subset in your DSL, this can
usually be done.

~~~
taejo
Thanks! I didn't consider the fact that objects are opaque.

------
noobermin
First, I did not know this, it's pretty cool.

But, for all the fangled cool things that the more powerful languages of
yesteryears (like lisp), what seems to actually precipitate adoption is simply
history, not necessarily expressiveness/powerful abstractions, etc. See C, sh
and friends, javascript. Arguably, python is one where its ease made it
popular and it continues to develop language wise, albeit not without
controversy.

~~~
plafl
I was drawn to python because of the culture (simple, documentation) and I
stay because of the libraries (machine learning, scientific). The language
just needs to be better than Matlab or R (not Scheme, Clojure, Scala or pick
your favorite one). As in nature the language that thrives is the fittest for
its environment, not the most powerful.

~~~
correnos
> As in nature the language that thrives is the fittest for its environment,
> not the most powerful.

Now hold on. The most successful sprog of nature is humanity[citation needed]
and we're a case study in the fact that raw intelligence is more effective
than fitness for any particular niche. So: as in nature, there may be a bunch
of niche languages, but in time they'll find themselves with a conservation
status while a smart language rules the earth.

~~~
TeMPOraL
So tell me, how is it that Python and JavaScript now seem to rule the Earth,
instead of being locked up in a nature reserve?

~~~
erik_seaberg
When programming languages evolve, "can a human being understand this code?"
is part of the fitness function, and more succinct and powerful languages
aren't always best for that.

------
RangerScience
Fascinating. An amazing point about design patterns, and yet...

Declarative statements are a pattern in ruby - you see them everywhere
(`attr_accessor`). They're library code - you're intended to write them. I
can't imagine trying to write ruby _without_ that pattern, and I can't imagine
them not being a design pattern.

Similarly - the MVC of Rails. The lines get way fuzzier, but you still might
try to draw similar lines to separate the core framework (badly analogous to
the language) from, I guess, all the gems you end up using (badly analogous to
the library). Is MVC a pattern? Or under this bad analogy, a language
construct...?

~~~
pozorvlak
I was really trying to make a narrower point here - that there is a reasonable
way to distinguish "part of the language" from "part of the (standard)
library" \- but I'll bite :-)

attr_accessor, as it happens ([http://ruby-
doc.org/core-2.0.0/Module.html#method-i-attr_acc...](http://ruby-
doc.org/core-2.0.0/Module.html#method-i-attr_accessor)) is implemented in C
code, but one _could_ implement it in Ruby, so I'd count it as part of the
(standard) library, and creating accessors is just using a library method. In,
say, Java setters and getters have to be written by hand (or autogenerated by
some external system like an IDE), so they're a pattern. On the other hand,
the way Ruby translates `foo.bar = 3` into a call to `foo`'s `bar=` method is
not alterable by user code, so it's part of the language.

MVC in Rails is an interesting case. You have to create new classes according
to the pattern (either by hand or using `rails generate`), but there's also
some library support in the form of Model and Controller classes you're
expected to inherit from, and which handle much of the View/Controller
plumbing for you. I'd say it's still a pattern, though.

~~~
RangerScience
Oh, neat! It's always cool when the authors of content pop onto HN (I see from
you karma you're new here, welcome!)

Yeah - I heard your point when I first read your post, but it took some more
time and reading to understand it. It's a good distinction.

What I'm not getting is... So you've got a really precise and elegant line
between "language" and "library", but it's not clear what the difference is
between patterns and.... maybe idioms?

attr_accessor, has_many, and carrierwave's mount_uploader (to provide many
examples) are all examples of a "pattern" (in the sense of a repeated thing,
not a design pattern) in Ruby, but I can't determine what's then in need of
"fixing" or what abstraction features could be added to remove the "pattern".

~~~
pozorvlak
> I see from your karma you're new here, welcome!

You missed the "created: 3246 days ago" bit, then? :-) But you're right that I
don't spend much time here - thanks for the welcome!

> it's not clear what the difference is between patterns and.... maybe idioms?

You're right, it's not a clear distinction. But for our purposes, the
important point about design patterns is "must be reimplemented from scratch
for each use". Have you read the Gang of Four book? Their patterns all require
the programmer to define a bunch of new classes from scratch each time the
pattern is used. Compare the Decorator pattern
([https://en.wikipedia.org/wiki/Decorator_pattern](https://en.wikipedia.org/wiki/Decorator_pattern))
to Python's decorators - the pattern requires the programmer to create new
classes, forward methods, etc, but the Python feature requires the programmer
to write one line of code (which then does all the class-creation and method-
forwarding under the hood). The Python feature has successfully obviated the
need for the pattern. You still need to write the same amount of application-
specific business-logic code, but the machine handles all the tedious plumbing
for you. Similarly, attr_accessor and has_many handle the tedious plumbing of
getters/setters and collections-backed-by-join-queries, respectively. So the
necessary abstraction features have already been added, and there's nothing
left to fix. An interesting intermediate case is the Iterator pattern in
Python
([https://en.wikipedia.org/wiki/Iterator_pattern](https://en.wikipedia.org/wiki/Iterator_pattern)).
Python still has explicit iterators, but standardises the interface so library
code can make use of user-provided iterators. It also provides a convenient
language-level facility for building iterators, using generator syntax.
Haskell, arguably, has entirely absorbed iterators into the language,
replacing them with lazy lists.

It's worth noting that the key property of Ruby that allows for things like
attr_accessor is the ability to add methods and fields to an object or class
at runtime, and thus to do so programmatically. Lisp can similarly dispense
with a lot of patterns that are necessary in Java, because Lisp has compile-
time code generation in the form of macros. Peter Norvig's talk on this is
great: [http://norvig.com/design-
patterns/ppframe.htm](http://norvig.com/design-patterns/ppframe.htm)

~~~
RangerScience
> You missed the "created: 3246 days ago" bit, then? :-)

Tots did. Errr... welcome, travelling from the land of Lurk?

> You're right, it's not a clear distinction...

Still, does the naming sound right? Patterns that get "encoded" into the
language, or made trivial by abstraction features within the language, are
idioms?

> Have you read the Gang of Four book?

No :/ The closest I've come, weirdly, was _tutoring_ a friend through a design
pattern class. Each time she'd come up and say, "The name of this week's
pattern is such-and-such", and from that, I'd get 90% of the way to knowing
that pattern was. I've always wanted just a simple list of the names, maybe
with linked single paragraph descriptions, but every prior time I've looked I
haven't been able to find one.

> add methods and fields to an object or class at runtime

Yes! That's a favorite Ruby trick. Straight up tho - what is the formal name
of doing that, specifically, the formal name of the category to which
attr_accessor and has_many belong to?

~~~
pozorvlak
> Patterns that get "encoded" into the language, or made trivial by
> abstraction features within the language, are idioms?

Yeah, that sounds like a reasonable term to use.

> The closest I've come, weirdly, was tutoring a friend through a design
> pattern class.

It's a bit old now, but I think it's probably still worth reading the GoF book
- it's clearly written, and much better than most subsequent imitators. In
particular, each pattern comes with a "when not to use this" discussion, that
more people should pay attention to :-/

> I've always wanted just a simple list of the names, maybe with linked single
> paragraph descriptions

Would
[http://wiki.c2.com/?CategoryPattern](http://wiki.c2.com/?CategoryPattern) do?

> what is the formal name of doing that, specifically, the formal name of the
> category to which attr_accessor and has_many belong to?

I'm not sure. Adding methods to a class at runtime is called "metaprogramming"
(which has the more general meaning of "writing code that writes or modifies
code"). I don't know of a name for a method that performs metaprogramming,
though.

------
rahoulb
Years ago I started (and didn't get very far) on a pointless project to make
Smalltalk look a bit more conventional without breaking how it works.

Including an if message that looks like if in C or similar language and and
unless construct that looks like Ruby.

[https://github.com/threehv/gstr/blob/master/README.markdown](https://github.com/threehv/gstr/blob/master/README.markdown)

------
lacampbell
I wish some of these ideas would bleed into the mainstream. A small simple
powerful core language and the minimum possible special syntax.

~~~
shakna
Clojure? It certainly has more syntax than many lisps, but still quite small.
(And used in the mainstream world).

------
RangerScience
The "response by Ralph Johnson" link is dead:
[http://www.cincomsmalltalk.com/userblogs/ralph/blogView?entr...](http://www.cincomsmalltalk.com/userblogs/ralph/blogView?entry=3335803396)
:/

~~~
pozorvlak
Thanks - I've noted that in the post.

~~~
RangerScience
Do you remember what the title of that post was? We may be able to track down
a copy, given more information.

~~~
pozorvlak
I'm afraid not, and Googling for quotes from the post only shows up Mark
Dominus' post. Also, the Wayback Machine doesn't have a copy :-(

------
philippeback
There is a MOOC on Pharo available
[http://files.pharo.org/mooc/](http://files.pharo.org/mooc/)

French speaking but PDFs are in english.

------
rimliu
Somewhat relevant:
[https://www.youtube.com/watch?v=29MAL8pJImQ](https://www.youtube.com/watch?v=29MAL8pJImQ)

------
brudgers
Date: 2008

~~~
ColinWright
Do you think it's now invalid? Do you think anything has changed? I'd be
interested to hear of any news that you think would update this.

~~~
brudgers
Not at all, and that's why I upvoted it.

I mentioned the date because it is traditional in titles. Here it might put
comparisons to ES9 and complaints about display on the iPhone 10s in context
(I'm optimistic). Pessimistically, it might give fair warning that hyperlinks
from the page 404.

~~~
pozorvlak
Thanks! I've now updated the post to reflect some corrections here, and to
point out the 404ing link.

