Something something linearization...

157 views
Skip to first unread message

Nils Kilden-Pedersen

unread,
Jul 21, 2016, 4:25:13 AM7/21/16
to dotty-internals
I'm not sure why this syntax isn't available in Scala currently, but is there any chance to get it included in Dotty?

trait Bar {
  def bar(): Int
}

trait Twice extends Bar {
  abstract override def bar(): Int = super.bar() * 2
}

class Foo {
  def bar(): Int = 42
} with Twice

Alex Cruise

unread,
Jul 21, 2016, 12:22:53 PM7/21/16
to Nils Kilden-Pedersen, dotty-internals
On Thu, Jul 21, 2016 at 4:25 AM, Nils Kilden-Pedersen <nil...@gmail.com> wrote:
I'm not sure why this syntax isn't available in Scala currently, but is there any chance to get it included in Dotty?

I'm sure I speak for many people when I ask...

Why?

:)

-0xe1a

Josh Suereth

unread,
Jul 21, 2016, 12:55:45 PM7/21/16
to Alex Cruise, Nils Kilden-Pedersen, dotty-internals
I think you'd probably just want to use trait parameters for that:

trait Bar(bars: Int) {
  def bar: Int = bar
}
trait Twice extends Bar {
  override def bar: Int = super.bar *2
}
class Foo extends Twice with Bar(42)

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

Nils Kilden-Pedersen

unread,
Jul 21, 2016, 5:45:11 PM7/21/16
to dotty-internals, nil...@gmail.com

Sorry, I thought that was obvious.

Because it would be nice to provide a class that already has the trait mixed-in, so you don’t have to do that every single time you do new.

So let me ask the opposite question: Why would you be satisfied with having to manually apply a trait, when a solution could exist that had it mixed-in by default?


:)
 

:)

-0xe1a

Nils Kilden-Pedersen

unread,
Jul 21, 2016, 6:02:18 PM7/21/16
to dotty-internals, al...@cluonflux.com, nil...@gmail.com
On Thursday, July 21, 2016 at 6:55:45 PM UTC+2, Josh Suereth wrote:
I think you'd probably just want to use trait parameters for that:

trait Bar(bars: Int) {
  def bar: Int = bar
}
trait Twice extends Bar {
  override def bar: Int = super.bar *2
}
class Foo extends Twice with Bar(42)

So, are you saying that instead of having Bars methods be abstract, they should instead be implemented by delegating to trait parameter functions?

I guess that would work, but at the cost of a rather weird syntax. And also, the trait no longer works as an abstract override, so I probably have to define it twice (no pun intended).

Also, let’s make the example a little more realistic:

trait Bar(_calculate: (Double, Double, Double) => Double, _process: (Int, String) => Long) {
  def calculate(x: Double, y: Double, z: Double): Double = _calculate(x, y, z)
  def process(a: Int, b: String): Long = _process(a, b)
}
trait Twice {
  def calculate(x: Double, y: Double, z: Double): Double = super.calculate(x*2, y*2, z*2)
  def process(a: Int, b: String): Long = _process(a*2, b+b)
}
object Foo {
  def calculate(x: Double, y: Double, z: Double): Double = {
    // Complex calculation
  }
  def process(a: Int, b: String): Long = {
    // Lengthy process
  }
}
class Foo extends Twice with Bar(Foo.calculate, Foo.process)

So boilerplatey I almost long for Java.

So, is there any good reason why my first example, which is succinct, readable, and, I think, clearly understood, isn’t, or shouldn’t be, allowed syntax?

Nils Kilden-Pedersen

unread,
Jul 21, 2016, 6:07:51 PM7/21/16
to dotty-internals, nil...@gmail.com
Let me further elaborate. The cake pattern is a good pattern, in that it allows mixing together various concerns into a single instance. The cake pattern is a bad pattern because that often becomes unwieldy and hard to understand. Being able to provided pre-baked cakes would be of great help in this regard.
 

:)
 

:)

-0xe1a

Paolo Giarrusso

unread,
Oct 28, 2016, 12:27:02 PM10/28/16
to dotty-internals
First of all, I think this example can be encoded as:
trait FooT extends Bar {
  def bar(): Int = 42
}
class Foo extends FooT with Twice

That encoding is much more faithful. Is there some example where it's not enough? (I might have a different one below).

I also think I got where you're coming from. If we pretended that

class Name extends SuperTraits { body }

simply meant

type Name = SuperTraits with { body }

Now, it also makes sense to have:

type Name = { body } with SuperTraits 

So by analogy we could want:
class Name { body } with SuperTraits

However, the JVM translation gives a special place to { body }, since the JVM doesn't support mixins directly.

* This example relies on abstract override, because otherwise 
class Foo extends Twice {
 def bar(): Int = 42
}
would work (and I'm not sure it won't work here).

* A related annoyance (which gets in the way when using the cake pattern) is that SuperTraits must be trait or class names, not names of types that immediately expand to (refined) traits. I've run into that limitation somewhat, and that should be fixable. Concretely, you can't do:
type Blip = Bar with { type T = Baz }
class Foo extends Blip

You can try 
trait Blip extends Bar { type T = Baz }
class Foo extends Blip

but then new Bar { type T = Baz } is not a subtype of Blip, and this gets in the way sometimes.

Nils Kilden-Pedersen

unread,
Nov 3, 2016, 12:36:47 PM11/3/16
to Paolo Giarrusso, dotty-internals
On Fri, Oct 28, 2016 at 11:27 AM, Paolo Giarrusso <p.gia...@gmail.com> wrote:


On Thursday, July 21, 2016 at 10:25:13 AM UTC+2, Nils Kilden-Pedersen wrote:
I'm not sure why this syntax isn't available in Scala currently, but is there any chance to get it included in Dotty?

trait Bar {
  def bar(): Int
}

trait Twice extends Bar {
  abstract override def bar(): Int = super.bar() * 2
}

class Foo {
  def bar(): Int = 42
} with Twice
First of all, I think this example can be encoded as:
trait FooT extends Bar {
  def bar(): Int = 42
}
class Foo extends FooT with Twice

That encoding is much more faithful. Is there some example where it's not enough? (I might have a different one below).

Well, it’s sort of annoying having to make two declarations, when the syntax could be made available for that not to be necessary.

However, my example was probably poor, as I feel this is more an annoyance when dealing with anonymous classes that need some trait behavior applied.

So, e.g. this would be nice:

def newBar(b: Int): Bar = new Bar { def bar = b } with Twice

Instead, I have to do this:

def newBar(b: Int): Bar = {
  class AnonBar extends Bar {
    def bar = b
  }
  new AnonBar with Twice
}

Not the end of the world, but the syntax seems inconsistent, and it’s more noisy boiler-plate.

 

I also think I got where you're coming from. If we pretended that

class Name extends SuperTraits { body }

simply meant

type Name = SuperTraits with { body }

Now, it also makes sense to have:

type Name = { body } with SuperTraits 

So by analogy we could want:
class Name { body } with SuperTraits

However, the JVM translation gives a special place to { body }, since the JVM doesn't support mixins directly.

* This example relies on abstract override, because otherwise 
class Foo extends Twice {
 def bar(): Int = 42
}
would work (and I'm not sure it won't work here).

* A related annoyance (which gets in the way when using the cake pattern) is that SuperTraits must be trait or class names, not names of types that immediately expand to (refined) traits. I've run into that limitation somewhat, and that should be fixable. Concretely, you can't do:
type Blip = Bar with { type T = Baz }
class Foo extends Blip

You can try 
trait Blip extends Bar { type T = Baz }
class Foo extends Blip

but then new Bar { type T = Baz } is not a subtype of Blip, and this gets in the way sometimes.

--
You received this message because you are subscribed to the Google Groups "dotty-internals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dotty-internals+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages