HNHacker News
TopNewBestAskShowJobs

gavinking

159 karma · joined December 20, 2011

submissionscomments
gavinking··on Constructors in Ceylon
> Yes, just for clarification, that was my point.

OK cool. Then my response is simply that we took a whole lot of community feedback, as always, over a span of years, both on the issue tracker and on our Gitter (previously IRC) channel. People with a wide range of programming experience contributed to this discussion.

No, I did not look closely at Scala's constructors. I did look at some other languages which are a bigger influence on me, some of which do things very differently to Ceylon.

> You're certainly having to defend yourself a lot in the other comments, so I don't want to continue that.

Thanks :-/

gavinking··on Constructors in Ceylon
> fact is that constructors are called on the class/type, and not on the instance.

But this is the case in Scala too. So I really don't understand the distinction you're trying to make.

> No, because it is good design to have one entry-point to create an instance, not 5.

I don't understand how having a factory method on a Scala companion object that calls an overloaded constructor of a Scala class is not a separate "entry-point". I count each of those factory-method-constructor bundles as one entry-point. And even if these factory methods all call the same constructor, they still seem like separate "entry-point"s.

And apart from your assertion that a single "entry-point" is good design, I don't quite see any particular reason to believe it. You've offered no arguments for this assertion.

> In Scala you have one place for "static" things. In Ceylon, static is all over the place:

Scala has members of objects and constructors of classes. Ceylon has members of objects and constructors of classes. Where is the difference? OK, so in Ceylon I can have a constructor which does not declare any parameters. How does that amount to being "all over the place" compared to Scala.

> Yes. Ceylon wasted the "good" syntax on the wrong construct. Most of the patterns leveraged in factory methods are just not available in Ceylon, because the best syntax was directly married to the class.

Well you see this is where Scala starts to look really bad. The problem is that Scala has no plain functions. Scala forces you to write methods of objects. In Ceylon we have toplevel functions, so we just don't need to go around sticking functions on the side of classes like you do in Scala.

> Everything Ceylon has built into "constructors" are just standard methods with no magic required in Scala.

This is simply false. You can't emulate constructors with plain methods in a language which enforces immutability / single-assignment. If you could, we would have done it that way.

> Yes, constructors are not extremely powerful – because they don't need to be in Scala.

Well, I never claimed that Scala needed constructors. Indeed I never mentioned Scala until people started trying to say—incorrectly to the point of absurdity, as it turns out—that Ceylon had copied its system of constructors from Scala.

Indeed you were one of those people. You entered this discussion with the following attack on me:

> A language designer which doesn't want to give credit where credit is due

I'm still waiting for you to retract that, now that I've conclusively demonstrated that Ceylon's constructors are totally different to—and more powerful than—Scala's.

gavinking··on Constructors in Ceylon
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.

gavinking··on Constructors in Ceylon
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.
gavinking··on Constructors in Ceylon
> Nobody needs or wants the mess of Java-style initialization Ceylon tries to replicate.

Initialization in Ceylon is nothing like initialization in Java:

- For the simple (common) case where there is exactly one initialization path, Ceylon is far less verbose.

- In Ceylon, the compiler guarantees that ever field not marked variable is assigned exactly once.

> Yet another static thing in class declarations?

Not really, just a constructor with no parameters.

Constructors are not "static". Constructors access the members of the class.

> Constructors in Scala are intended to directly initialize fields.

But it seems to me that they can't. Isn't it correct that only the primary constructor can initialize vals?

> Constructors in Scala are intended to directly initialize fields. They shouldn't be called directly, and are often private.

AFAICT it is not a limitation of the Scala language that constructors shouldn't be called directly. If it's indeed a practice that constructors aren't called directly, then it's interesting to enquire why that might be. And indeed an answer presents itself: because they don't have names.

> Factory methods provide everything else, and are declared in objects, instead of being static like in Ceylon.

Wait: a factory method declared on a "companion object" is not like static?! Really?

And it seems to me that people probably hide constructors behind factory methods precisely because constructors in Scala don't have names. I mean AFAICT, the syntax for calling a factory method of a companion object in scala is exactly the same as the syntax for calling a constructor in Ceylon! You just have to go through a whole lot more ceremony in Scala.

> Scala did away with 90% of the mess associated with constructors

And, AFAICT, also lost like 75% of their capabilities. Unless my evaluation above is wrong, and I'm missing something. But so far no-one has spoken up to correct me.

> therefore have a nice day! :-)

You too!

gavinking··on Constructors in Ceylon
Right, so at that point, as I say, there's really not much daylight between "class" and "record". The difference being that a class protects its initialization logic (favoring modularity), whereas a record opens it up (favoring flexibility).

Ultimately I see them as much more similar than they are different.

gavinking··on Constructors in Ceylon
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.

gavinking··on Constructors in Ceylon
Well the issue in my mind is how to functionally decompose construction of a record. You have to come up with some way to express a "partial" record, and then "augment" it with new members. I'm trying to say this without using the word "inheritance" ;-)
gavinking··on Constructors in Ceylon
Wait, wait, wait: just two hours ago you were demanding that I give credit to Scala for the design of constructors in Ceylon. And you accused me of quote "just tweaking of the language's constructor patterns and calling it novel".

It seems that you now accept that in fact the two designs are dissimilar, and that Ceylon's is significantly more powerful.

So, before continuing this discussion, do you think it would appropriate to start by apologizing to my team?

Just so we don't get off on the wrong foot?

gavinking··on Constructors in Ceylon
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?
gavinking··on Constructors in Ceylon
Well in fact constructors aren't that much like static methods at all. Now static methods really are a weird thing, because they break the block structure of the language: they look like they have access to members of the class, but they don't.

That's why Ceylon doesn't have static methods.

Constructors, OTOH, actually fit in with the block structure of the language. They do have access to the members of the class, and the responsibility to initialize those members.

Now, the interesting thing is that I spend 4 years of my life hoping that we would not need constructors, and that the ability to initialize a class via the parameter list of the class would be sufficient for all usecases.

Sadly, it turns out that I was wrong about this, and that, in practice, there are some really good usecases for constructors in a language which emphasizes immutability as Ceylon does. That's just what we ran into in practice.

> you said you didn't look into that other language

I never said that. Please don't put words into my mouth.

FYI, I've looked closely at lots of other languages, including languages like OCaml and F# and Rust which do things quite differently to Ceylon. I like those approaches, and they have advantages/disadvantages compared to constructors. I would not say they are clearly better, nor clearly worse. But I'm confident that what we have done is very clean and elegant and powerful in the context of Ceylon.

gavinking··on Constructors in Ceylon
I understand, but once you start taking into account other requirements, like the ability to functionally decompose construction of this record, you will wind up with something that looks painfully similar to a class in Ceylon.
gavinking··on Constructors in Ceylon
So if you scroll down, you'll find my tentative evaluation of Scala's support for constructors. I have not found anything of interest there. Indeed, if my understanding is correct, constructors in Scala have extremely limited capabilities, since all initialization ultimately flows through the primary constructor which is responsible for initializing all fields. In Ceylon we obviously had a more ambitious set of requirements.
gavinking··on Constructors in Ceylon
The equivalent of Scala's case classes is an enumerated class with an "of" clause. Constructors aren't really relevant here, AFAICT.
gavinking··on Constructors in Ceylon
OK, so, here’s a tentative list of similarities / differences. Please correct me if I've made a mistake.

Similarities:

- Scala has the notion of a “primary” constructor vs “auxiliary” constructor, which at first looks sorta superficially similar to the notion of a “default” vs “named" constructor in Ceylon.

- Both Ceylon and Scala (and Java, and C++, and C#, etc) have a notion of delegation between constructors.

Differences:

- In Scala, constructors are overloaded, that is, they are distinguished by the types of their parameters. In Ceylon, they have distinct names, and are distinguished by name.

- In Scala, every auxiliary constructor of a class must ultimately delegate to the primary constructor. In Ceylon, there is is no such restriction. Any constructor may delegate directly to the superclass. Given this, I can't see how it's possible for two constructors of a Scala class to delegate to different constructors of the superclass. That's possible in Ceylon.

- In Scala I could not find any way to assign to an immutable member (val) from an auxiliary constructor. At first I thought that this could not possibly be a real limitation, but, checking stack overflow, it seems that it is. Auxiliary constructors can only assign to vars? Really?!

- In Ceylon, initialization flows from the top of the class body to the bottom, allowing. In Scala it jumps around: all statements of the primary constructor are executed, even statements that occur after the auxiliary constructors, and then the auxiliary constructors.

- Ceylon has the notion of a partial constructor which partially initializes the class, but may only be called by other constructors. Scala doesn’t seem to have this concept. Indeed, the primary constructor must initialize all fields. And, if I understand correctly, the only thing that auxiliary constructors are allowed to do is mess with mutable members and perform side-effects. (Of course, it’s a bad practice to make constructors side-effecty.)

- Ceylon has the notion of a value constructor. I have not yet found anything like that in Scala.

- Taking a reference to a constructor and treating it as a function seems to be quite uncomfortable in Scala. In Ceylon it's very natural. Also Scala sometimes seems to demand the use of the "new" operator in instantiation expressions, though I'm not clear why that's a requirement.

My bottom line conclusion is that constructors in Scala are much less powerful than I had imagined they would be, and, it seems, much less powerful than constructors in Ceylon. Of course, some of what I’ve written here could be incorrect, since I’m not a Scala programmer. If so, I’m hoping someone will correct me.

Anyway, I definitely haven’t found anything in Scala constructors that we should have reproduced in Ceylon. Can someone else find something?

gavinking··on Constructors in Ceylon
Well I guess it's not extremely clear to me how a "record literal with open recursion" isn't essentially the same thing as a "class".
gavinking··on Constructors in Ceylon
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.
gavinking··on Constructors in Ceylon
Wait, Scala's "case classes" are an implementation of what are called "sum types" in PL theory. Ceylon also has sum types, but they don't have anything much at all to do with _constructors_.

If you want to know about how Ceylon supports sum types, you can look here:

http://ceylon-lang.org/documentation/1.1/tour/types/

FYI, Scala didn't invent sum types, and they can be found in languages much older than Scala, going back to the 1970s, if I'm not mistaken.

Finally, I don't understand why you're repeating the claim that we're "just tweaking of the language's constructor patterns and calling it novel" when I've already responded and explained that the approach to constructors in Ceylon is quite different to Scala and wasn't influenced by Scala. Is it just a lame attempt to try and provoke me or do you have an actual point to make?

gavinking··on Constructors in Ceylon
OK, well it seems quite likley you're just trolling me here, but I'll respond anyway: do you have some technical feedback on how the design I've outlined here is flawed or inferior to some other "state of the art" design, or a link to some research that you think I didn't do?

Because if not, it doesn't seem that scary, does it?

gavinking··on Constructors in Ceylon
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.

gavinking··on Constructors in Ceylon
Yes of course. I'm at the gym right now, so give me a chance to get home, read up on Scala so I can be sure I'm not saying anything wrong, and then I'll reply. Is that OK?
gavinking··on Constructors in Ceylon
Yeah, OK, I just had a quick look, and Scala constructors seem to have almost nothing in common with the design I outline in this blog, other than being, well, constructors. Perhaps you didn't read the linked article?
gavinking··on Constructors in Ceylon
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?

gavinking··on Constructors in Ceylon
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?

gavinking··on Constructors in Ceylon
Right, exactly. So there's two very distinct cases here:

- the simple and overwhelmingly common case where there is only one way to instantiate a class, and therefore there is no reason to decouple the body of the class from the parameter list, and

- the occasional but also important case where there are multiple ways to instantiate the class, each with different parameter list signatures, where we need to decouple the body of the class from the parameter list signatures.

"Constructors" as supported in Java, C++, C#, and now also in Ceylon, are optimized for the "occasional" case. And I'm convinced that they're useful enough that we need them. But in the "overwhelmingly common" case they get in the way, and that's why they're not the usual thing you reach for first when writing a class in Ceylon.

gavinking··on Constructors in Ceylon
Totally this!
gavinking··on Constructors in Ceylon
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.

gavinking··on Constructors in Ceylon
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.

gavinking··on Friends Don't Let Friends Clap on One and Three: A Backbeat Clapping Study
Well both are wrong. You don't clap on two and four; you click your fingers. I thought everyone knew that...
gavinking··on Ceylon 1.1.0 is now available
Cheers!
← PreviousPage 2 of 4Next →