Deprecating “optional extends”?

261 views
Skip to first unread message

Simon Ochsenreither

unread,
Dec 6, 2013, 2:44:32 PM12/6/13
to scala-i...@googlegroups.com
Hi,

this came up in the thread “weird inheritance”: https://groups.google.com/forum/#!topic/scala-user/_qMoODIBQtE

Congratulations to som-snytt for teaching me yet another arcane detail of the language. :-)

Imho, the optional extends is unnecessarily confusing and doesn't add anything to the language except another way to do exactly the same thing.

I suggest deprecating it.

Bye,

Simon

Paul Phillips

unread,
Dec 6, 2013, 3:11:07 PM12/6/13
to scala-i...@googlegroups.com
That would mean if you have this

class Foo extends { val earlyDef = 1 } with Bar

and you remove the "with Bar", it stops compiling. Intuitively that shouldn't be the case. Not amazingly important, but it's the kind of thing people almost never think of. (OH HOW I MISS THE TRAILING COMMA.)

I just noticed an unrelated thing with early defs, maybe not that surprising but...

class Foo { val bar = 1 }
class Bar extends { override val bar = 2 } with Foo
class X1 extends { override val bar = 3 } with Bar
class X2 extends Bar { override val bar = 3 }

The way Bar is written, the author probably imagined they were safe that in Bar's constructor val bar = 2. But for class X2, it's 0. The bar is demoted from the land of early definitions and retains the uninitialized value until X2 sets it. In X1, it is 3 everywhere.

I wonder if there's a good reason a normal definition should be able to override an early definition. If early could only be overridden by early there would be less room for surprise.

OlegYch

unread,
Dec 7, 2013, 12:59:02 PM12/7/13
to scala-i...@googlegroups.com
Do you want to make extends non-optional (which imo would be confusing) or to prohibit extends without ClassTemplate ?
On a related note, how about deprecating "extends" in favor of "with" everywhere?

Thanks, Aleh

PS i do miss the trailing comma

Simon Ochsenreither

unread,
Dec 7, 2013, 3:07:47 PM12/7/13
to scala-i...@googlegroups.com

Do you want to make extends non-optional (which imo would be confusing) or to prohibit extends without ClassTemplate?

‘extends’ ClassTemplate | [[‘extends’] TemplateBody]
        |
        v
‘extends’ ClassTemplate | [TemplateBody]

Simon Ochsenreither

unread,
Dec 8, 2013, 11:43:52 AM12/8/13
to scala-i...@googlegroups.com
Martin, what's your opinion? SHall we deprecate it for 2.11?

An additional point why getting rid of it is that it's too easy to confuse with early initializers if the user doesn't read things carefully enough. (See also the other thread where this already happened.)

martin odersky

unread,
Dec 8, 2013, 12:02:04 PM12/8/13
to scala-internals
On Sun, Dec 8, 2013 at 5:43 PM, Simon Ochsenreither <simon.och...@gmail.com> wrote:
Martin, what's your opinion? SHall we deprecate it for 2.11?

I'd be in favor to leave it as is. 

  class C extends { ... }

makes sense. It defines a class type which is a subtype of the type in the braces. You could argue that

  class C { ... }

is the irregular form, which is nevertheless good to have, because it is shorter. So I think little is gained by changing things now.

Cheers

 - Martin



 
An additional point why getting rid of it is that it's too easy to confuse with early initializers if the user doesn't read things carefully enough. (See also the other thread where this already happened.)

--
You received this message because you are subscribed to the Google Groups "scala-internals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-interna...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



--
Prof. Martin Odersky
LAMP/IC, EPFL
Station 14, 1015 Lausanne, Switzerland
Tel: +41 21 693 6863

Simon Ochsenreither

unread,
Dec 8, 2013, 12:11:51 PM12/8/13
to scala-i...@googlegroups.com

I'd be in favor to leave it as is. 

  class C extends { ... }

makes sense. It defines a class type which is a subtype of the type in the braces. You could argue that

  class C { ... }

is the irregular form, which is nevertheless good to have, because it is shorter. So I think little is gained by changing things now.

Maybe it makes sense to grep over the corpus of Scala sources and have a look at how much it is used. Imho, it would make sense to get rid of one of the two syntactic options which do the same thing. I'd be in favor of the one whose usage is probably it 0.0001% and is inconsistent with pretty much every other class-based language out there.

Jon Pretty

unread,
Dec 9, 2013, 6:07:10 AM12/9/13
to scala-i...@googlegroups.com
I would side with Simon on this, not so much because it matters (it's a really minor point), but the decision would be consistent with the deprecation of redundant commas in argument lists.

Jon

martin odersky

unread,
Dec 9, 2013, 6:54:34 AM12/9/13
to scala-internals
It's more than how often it is used. If you deprecate `extends` the next question will be, why

  class C extends Trait1 with Trait 2 { ... }

and not

  class C with Trait1 with Trait2 { ... }

We had this discussion many, many times before; it's a very common objection. The one argument that
carries water here is that

    class C extends Trait1 with Trait2 { ... }

parses conceptually as

    class C extends <<< Trait1 with Trait2 { ... } >>>

But that argument breaks down if

    class C extends { ... }

is illegal. So unless we want to unravel the whole idea of `extends`, we need to leave it in place.

Cheers

 - Martin



--
You received this message because you are subscribed to the Google Groups "scala-internals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-interna...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Jon Pretty

unread,
Dec 9, 2013, 7:18:25 AM12/9/13
to scala-i...@googlegroups.com
Hi Martin,

That's perfectly sensible, and would be even moreso if "with" were replaced by a symbolic operator - say `&` - so that extends and with/& have more obviously different precedence. You might have already thought of this... ;)

Cheers,
Jon

Kevin Wright

unread,
Dec 9, 2013, 7:35:19 AM12/9/13
to scala-internals
Well.. The spec of the DOT calculus uses /\ and \/ for type union/intersection operations (for that matter, so does shapeless and scalaz)

So you might well see a symbolic for in Scala 3.x, presumably using `with` as an alias for backwards compatibility.

martin odersky

unread,
Dec 9, 2013, 7:40:53 AM12/9/13
to scala-internals
On Mon, Dec 9, 2013 at 1:35 PM, Kevin Wright <kev.lee...@gmail.com> wrote:
Well.. The spec of the DOT calculus uses /\ and \/ for type union/intersection operations (for that matter, so does shapeless and scalaz)

So you might well see a symbolic for in Scala 3.x, presumably using `with` as an alias for backwards compatibility.

In fact, no. I think you will see a &(and |) as operator on types, but not for the parents of a superclass. & will be true intersection, which means also that it's commutative. `with` means linearization of parents, which is not commutative. So in fact I think it's preferable to have two distinct operators.

Cheers

 - Martin

--
You received this message because you are subscribed to the Google Groups "scala-internals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-interna...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Kevin Wright

unread,
Dec 9, 2013, 7:41:20 AM12/9/13
to scala-internals
Although...  It will kind of cramp people's style if they're forced to use unicode characters here.  Harder to type and not supported by all that many monospaced fonts.  So we'd have to support using slashes to make these characters in addition to the "correct" unicode forms.

This becomes even more important when we remember that any font which doesn't also support √ will never be accepted by Viktor :)

Jan Vanek

unread,
Dec 9, 2013, 7:45:49 AM12/9/13
to scala-i...@googlegroups.com
If you don't deprecate extends (I agree), shouldn't this also be possible?

  class C extends T with { val a: Int }

With regards,
Jan

martin odersky

unread,
Dec 9, 2013, 8:04:53 AM12/9/13
to scala-internals
On Mon, Dec 9, 2013 at 1:45 PM, Jan Vanek <j3v...@gmail.com> wrote:
If you don't deprecate extends (I agree), shouldn't this also be possible?

  class C extends T with { val a: Int }

It's a close call, but I would say, no. 

    { val a: Int }

is a refinement; it applies to the type that comes before. If that type is missing, we assume AnyRef. But

    class C extends T with AnyRef { val a: Int }

would not be well-formed.

Cheers

 - Martin

Matthew Pocock

unread,
Dec 9, 2013, 8:37:20 AM12/9/13
to scala-i...@googlegroups.com
So as somebody who isn't up to my armpits in the scala type theory, this is all quite confusing. I wrote more about why it is confusing, but it confused me so I deleted it. Why are there things that look like structural types before the body of a class? Why are they allowed? What compelling functionality do they deliver?

Matthew
Dr Matthew Pocock
Turing ate my hamster LTD

Integrative Bioinformatics Group, School of Computing Science, Newcastle University

skype: matthew.pocock
tel: (0191) 2566550

Jan Vanek

unread,
Dec 9, 2013, 8:54:35 AM12/9/13
to scala-i...@googlegroups.com
On Mon, Dec 9, 2013 at 2:04 PM, martin odersky <martin....@epfl.ch> wrote:



On Mon, Dec 9, 2013 at 1:45 PM, Jan Vanek <j3v...@gmail.com> wrote:
If you don't deprecate extends (I agree), shouldn't this also be possible?

  class C extends T with { val a: Int }

It's a close call, but I would say, no. 

    { val a: Int }

is a refinement; it applies to the type that comes before. If that type is missing, we assume AnyRef. But


I see, thanks.

Jon Pretty

unread,
Dec 9, 2013, 8:54:54 AM12/9/13
to scala-i...@googlegroups.com
Hi Matthew,

I use early initializers in a couple of places in Rapture.

Here's one simplified use-case:

  class StringOutput extends {
    private val sw = new StringWriter
  } with CharOutput(sw) {
    def buffer: String = sw.toString
  }

I need to be able to refer to the same `sw` in the parameter to `CharOutput` and in the definition of `buffer` (where the parameter to `CharOutput` is only a constructor parameter, not a member).

Jon

martin odersky

unread,
Dec 9, 2013, 9:00:02 AM12/9/13
to scala-internals
On Mon, Dec 9, 2013 at 2:54 PM, Jon Pretty <googl...@accounts.propensive.com> wrote:
Hi Matthew,

I use early initializers in a couple of places in Rapture.

Here's one simplified use-case:

  class StringOutput extends {
    private val sw = new StringWriter
  } with CharOutput(sw) {
    def buffer: String = sw.toString
  }

I need to be able to refer to the same `sw` in the parameter to `CharOutput` and in the definition of `buffer` (where the parameter to `CharOutput` is only a constructor parameter, not a member).

Jon

I agree that early definitions are confusing. They are necessary right now, because there's no other way to ensure that certain things are initialized before an initializer of a trait is run. 

The plan is to look into traits that can have parameters, like classes can. In that case, we would not need early definitions anymore, because the parameter mechanism would be good enough.

Cheers

 - Martin

Jon Pretty

unread,
Dec 9, 2013, 9:15:46 AM12/9/13
to scala-i...@googlegroups.com
On Monday, 9 December 2013 14:00:02 UTC, martin wrote:
The plan is to look into traits that can have parameters, like classes can. In that case, we would not need early definitions anymore, because the parameter mechanism would be good enough.

A trait with parameters?! It's been a long time since I last saw one of them! Though I never really experienced the problems they introduced (which resulted in their removal the first time). If it's workable, that would bring some welcome code tidyups...

Cheers,
Jon

OlegYch

unread,
Dec 9, 2013, 10:23:17 AM12/9/13
to scala-i...@googlegroups.com
Hi Martin

"extends" seems like a really redundant element in grammar. For example it is quite common to copy a list of 'with' clauses from one class definition to another and it's annoying to have to replace 'with' with 'extends' just because that list is now positioned directly after class name.
I'd welcome it's complete removal, and don't see any practical reason to not do it.

Thanks, Aleh

Som Snytt

unread,
Dec 9, 2013, 11:02:53 AM12/9/13
to scala-internals
soc will get a chance to deprecate early defs at some point, instead, right?  When parameterized traits are introduced.

Until then, rather than "pre-initialized fields," "early initializers," or "early definitions," we could call them whatever the French word is for "in lieu of parameterized traits."


--

Jon Pretty

unread,
Dec 9, 2013, 11:25:10 AM12/9/13
to scala-i...@googlegroups.com
On Monday, 9 December 2013 16:02:53 UTC, som-snytt wrote:
Until then, rather than "pre-initialized fields," "early initializers," or "early definitions," we could call them whatever the French word is for "in lieu of parameterized traits."

How funny that there should be a French word for "in lieu of"...

If they're going away, and not many people know about them anyway, it might be better just not to talk about them...

Cheers,
Jon

Som Snytt

unread,
Dec 19, 2013, 2:27:14 AM12/19/13
to scala-internals
This just popped up on SO.  Don't ask me why I'm browsing SO.  Because I had a cup of coffee this evening.

http://stackoverflow.com/q/20666264/1296806

But they came up with a great name for it: naked extends!

Naked extension sounds like a yoga asana of a certain practice.


--

Simon Ochsenreither

unread,
Dec 19, 2013, 3:02:34 AM12/19/13
to scala-i...@googlegroups.com
I'm still thinking that having the naked extends is a bad idea. If it is supposed to be there for consistency, the why doesn't

scala> class Foo extends Bar with { val foo = 42 }
<console>:1: error: identifier expected but '{' found.
       class Foo extends Bar with { val foo = 42 }
                                  ^


work the same way?!

martin odersky

unread,
Dec 19, 2013, 4:31:06 AM12/19/13
to scala-internals
A naked refinement 

    { ... } 

is a shorthand for 

   AnyRef { ... }

So 

    class C extends { ... }  

is a shorthand for  

    class C extends AnyRef { ... }

But

    class C extends A with { ... }  

would be a shorthand for 

   class C extends A with AnyRef { ... }

which is not well-formed.

Cheers

 - Martin



--
You received this message because you are subscribed to the Google Groups "scala-internals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-interna...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Nils Kilden-Pedersen

unread,
Dec 19, 2013, 7:57:57 AM12/19/13
to scala-i...@googlegroups.com
On Thu, Dec 19, 2013 at 10:31 AM, martin odersky <martin....@epfl.ch> wrote:
A naked refinement 

    { ... } 

is a shorthand for 

   AnyRef { ... }

So 

    class C extends { ... }  

is a shorthand for  

    class C extends AnyRef { ... }

It is still not clear to me if this is any different, conceptually, than this:

class C { ... }

To me, the former appears to be an extension of an anonymous class, whereas the latter is a regular class definition. The byte code makes no such distinction, 

Jon Pretty

unread,
Dec 20, 2013, 10:34:45 AM12/20/13
to scala-i...@googlegroups.com
Hi Martin,

In term of consistency, this looks a bit weird:

   class Foo(x: Int)

   // this compiles
   class Bar(y: Int) extends { val z = y + 1 } with Foo(z)

   // this does not
   class Baz(y: Int) extends AnyRef { val z = y + 1 } with Foo(z)

My surprise is mainly that the first version works...

Jon
Reply all
Reply to author
Forward
0 new messages