

Constructors in Ceylon - gavinking
http://ceylon-lang.org/blog/2015/06/21/constructors/

======
chriswarbo
Class hierarchies seem to me more and more like a shadow language[1]. I first
realised this in Python, where:

\- Classes can be called like functions

\- Calling a class runs a function (the constructor, called __init__)

\- The constructor is implicitly passed a fresh object as an argument (usually
called "self"; this is like an implicit use of "new")

\- The constructor implicitly returns an initialised object (a mutated "self")

In a language with first-class functions, it's also pretty arbitrary to define
"attributes" inside the constructor and "methods" outside, since methods are
functions which are values (modulo the implicit binding stuff).

Hence classes can be completely replaced by their constructors; or in other
words, classes are a design pattern when writing functions. This is a
realisation that's become mainstream due to Javascript, and that's the first
thing I thought of when I saw the Ceylon code in this article.

The details at the end, about execution order, partial constructors,
inheritance, etc. all screamed "shadow language" to me: if you've already got
functions(/methods), can't you just re-use them instead of defining a new,
semantically distinct category?

[1] [http://gbracha.blogspot.co.uk/2014/09/a-domain-of-
shadows.ht...](http://gbracha.blogspot.co.uk/2014/09/a-domain-of-shadows.html)

~~~
gavinking
Sure. A class is certainly a kind of function: one which returns a closure
over its own shared declarations. That's the way we conceptualize the notion
of a class in Ceylon, and it's why the syntax for a class looks so much like
the syntax for a function, and why there's no essential difference between a
function defined inside a class (a "method") and a function declared toplevel,
or inside another function, or whatever. Ditto for a value defined inside a
class (an "attribute") and a value declared toplevel or inside another
function. It's the same thing, as far as Ceylon is concerned.

One of the design goals in Ceylon was to treat all these things uniformly, so
that a class is, as much as possible, just like any other function.

However, there is a big and surprisingly important difference between a class
and a function that returns a record: with a class you get open recursion
between members of the class. You don't get that with a function that assigns
members to a record type - or, at least, if you do build the machinery you
need to get that, you have essentially reinvented classes with a worse syntax.

Open recursion seems like a small thing. But in fact, in practice, if you try
taking it away from me, I will have to do some convoluted and nasty things to
emulate it. Sure, there are plenty of simple classes where you can do without
it, but there are surprisingly many classes where it's necessary, or at least
very useful.

~~~
chriswarbo
> One of the design goals in Ceylon was to treat all these things uniformly,
> so that a class is, as much as possible, just like any other function.

That's reassuring to know, thanks :)

> However, there is a big and surprisingly important difference between a
> class and a function that returns a record: with a class you get open
> recursion between members of the class.

Record members are certainly bound too early to get open recursion, which is
why I claimed that classes == functions rather than objects == records ;)

In my example of Python, "objects" are abstract: created implicitly, passed
into the constructor, then (implicitly) returned.

> You don't get that with a function that assigns members to a record type -
> or, at least, if you do build the machinery you need to get that, you have
> essentially reinvented classes with a worse syntax.

I think there are a few distinctions to be made here:

\- Records vs. objects; which I've addressed above.

\- Syntax vs. semantics: I'm fine with special-purpose syntax, I just don't
like arbitrary _semantic_ distinctions. It sounds like Ceylon is better than
most in this regard :)

\- Built-in vs. library code: reinventing classes using functions is only a
bad idea if they're already built into the language in some other way. If
there's no built-in alternative, then doing this in a library is legitimate.
Likewise, using the language's existing support for functions to build-in a
class implementation is also legitimate, and it sounds like that's what
Ceylon's done :)

~~~
gavinking
Yes, I think that's certainly what we've tried to achieve. It sounds like you
and I have the same mental model, at least.

------
couchand
_As alluded above, the biggest problem with the constructor syntax in
languages that borrow from C++ is that in the common case of a class with just
one constructor, the parameters of that constructor aren 't available in the
body of the class, leading to awful code like the following:_

    
    
        class Point {
            public float x;
            public float y;
            public Point(float x, float y) {
                this.x = x;
                this.y = y;
            }
            public String toString() {
                return "(" + x + ", " + y + ")";
            }
        }
    

_This hurts. Fortunately, we 've already made that pain go away in Ceylon._

Well that seems like a laudable goal. Let's take a look at the example code,
then, to see what the alternative is:

    
    
        class Color {
    
            shared Integer rgba;
    
            //default constructor
            shared new (Integer rgba) {
                assert (0 <= rgba <= #FFFFFFFF);
                this.rgba = rgba;
            }
    
            ...
    
            string => "Color { \ 
                       alpha=``hex(alpha)``, \ 
                       red=``hex(red)``, \ 
                       green=``hex(green)``, \ 
                       blue=``hex(blue)`` }";
    
        }
    

Maybe it's just me but it looks like the pain is still there?

~~~
gavinking
No, the alternative is this:

    
    
        class Point(shared Float x, shared Float y) {
            string => "(``x``, ``y``)";
        }
    

I think I made that really clear in the post. In the very example I started
with, but perhaps I need to further clarify it somehow?

UPDATE: FTR, I added the above example to my post, in the hope that it
clarifies the point. Thanks for the feedback.

~~~
mikegioia
Why do all of your examples after the first violate the advantage you
reference in the first example?

~~~
gavinking
Because the post is dealing with the new functionality we've added in Ceylon
1.2, which provides support for Java-style (i.e. multiple) constructors, not
the functionality that has always existed in Ceylon, where parameters of the
class are listed at the top of the class declaration.

Does that make sense now?

------
duaneb
I think the name of the constructor itself may have merit eventually, but is
rather distracting from the function of the constructor itself.

Much of the rest of the work seems to mirror what Scala did several years ago,
and this seems to nearly replicate that. Considering the state of the scala
codebase, this again might have merit, but they do not even mention it once.
As such, I'm going to relegate this to the "branded language that will not
survive outside advertised setting" category because it seems to prioritize
positive comparisons over engineering use.

~~~
gavinking
So it seems to me that if you need multiple constructors then it's worth being
able to give them names, in order to identify their purpose.

I have never looked at how Scala handles constructors, beyond being dimly
aware that Scala has them, so I don't see why I should be expected to mention
Scala, when it had no influence at all on the design of this functionality. To
be clear, I find it highly unlikely that Scala constructors are very similar
to what I describe in this post, except perhaps on the most superficial level.
I will take a look at Scala later today to confirm that, just in case I'm
wrong.

I'm not sure what argument is being made in the rest of your comment. Perhaps
you could elaborate on what are your concerns?

~~~
stephen
Given you're a language designer, I'm really surprised you have not looked at
Scala enough to know how it handles constructors.

Scala is also your biggest competitor (IMO) on the JVM, which makes it even
more odd that you seem to not have looked at it deeply. (I'd understand not
reading the latest DOT type calculus/whatever paper, but this is basic
syntax/usage.)

Totally your call of course, but stealing the best ideas, in any endeavor, is
usually the best way to go. Even if you decide to not steal Scala's
constructors, that's fine, it's awesome if you have something better, but to
have not even evaluated them...

Just surprised.

~~~
gavinking
I guess I don't understand what you're saying here. I was already aware of the
concept of a constructor, from years of Java. And I already had a set of
really extremely tight design constraints in terms of the existing language
syntax and semantics, including a set of principles about how the block
structure of the language works, rules about definite initialization, the fact
we don't have overloading, etc, etc, which are quite specific to _Ceylon_, and
aren't found in other similar languages. These constraints were pretty much
sufficient to fully determine the resulting design.

Furthermore, there was an issue open in Ceylon's issue tracker for almost 2
years, following on from discussions and proposals in two other issues that go
back even further, and these issues were read and commented on by many of our
community members, including some who have some Scala experience.

Now, if you could point to some cool idea in Scala that we obviously aren't
aware of, and which could have improved the design of constructors in Ceylon,
then I guess you would have a point. But it doesn't seem like you do have
anything concrete, just a concern about _process_ rather than _outcome_.

And fundamentally I'm a guy who cares about outcome. And I think the outcome
is rather excellent.

~~~
jules
I think what they're saying is that it's good to give credit where credit is
due.

~~~
gavinking
Well since zero credit is due to Scala (read my post below where I utterly
demolish the claim that Ceylon constructors are similar to Scala) then doesn't
that seem like an utterly rude and obnoxious demand to you?

~~~
jules
If that were the case, yes, but it isn't. There are obviously some differences
but there are clearly also uncanny similarities.

~~~
gavinking
Name the "uncanny" similarities please. If you can't, I might think you're
trolling.

To be fair, it's nice to see you acknowledge that there are "obviously some
differences". Some tiny little subtle differences like how in Ceylon, I can
actually have two constructors that both initialize an immutable field. Like
how constructor resolution is by (unambiguous) name and not by (potentially
ambiguous) overloaded parameter types. Like how different constructors can
delegate to distinct constructors of the superclass. 'Cos, y'know, other than
that, it's really just a copy of Scala.

Absurd.

~~~
jules
I assumed duaneb was referring to the whole idea of giving parameters to the
class definition.

~~~
gavinking
Wait, you're not talking about constructors here. You're talking about the
idea of giving a class a parameter list? A feature that I independently came
up with about 7 years ago, before I - or most other people - had even heard of
Scala? And then implemented 5 years ago as one of like the very earliest
features in the Ceylon type checker? And which is not actually the topic of
the linked blog post? You're calling me out for copying _that_?!

Man, seriously, there is such a thing as two people coming up with the same
good idea independently. If you can't imagine such a thing happening, I'm at a
total loss.

~~~
jules
Certainly, it happens all the time. Leibniz and Newton invented calculus at
the same time. Scala is 12 years old though, and it's rare for a language
designer to not be aware of the main competitor in the same space, which is
probably why people assumed that you were aware of Scala.

Note that I personally couldn't care less who invented what, I just wrote what
I thought duaneb and stephen were getting at to clear up the confusion since
you said "I guess I don't understand what you're saying here."

------
perneto
Now that there is an apparently superior alternative, do you plan to do
something to eliminate the existing enum pattern explained at [http://ceylon-
lang.org/documentation/1.1/tour/types/#enumera...](http://ceylon-
lang.org/documentation/1.1/tour/types/#enumerated_instances) ?

~~~
gavinking
No, because that pattern is still strictly more powerful. With enumerated
classes I can have cases which are a class rather than just a singleton
instance.

------
kolev
Ceylon is my favorite language and I can't wait for v1.2 to be out! I just
wish it was catching up with JDK release a little faster and generally speed
up the release cycle. Spread the word, it definitely needs more love!

