structural type extending another structural type
Asked Answered
M

3

6

Why the following is not allowed? (2.12):

type Foo <: {def foo(): Unit}
type Bar <: {def bar(): Unit} with Foo

Looks natural to me, Bar should have both foo() and bar().

Misinform answered 12/9, 2020 at 4:47 Comment(2)
Dotty appears to allow it.Floppy
By the way, <: is not extending (inheriatance) but subtyping. cmi.ac.in/~madhavan/courses/pl2009/lecturenotes/lecture-notes/…Meadowlark
M
8

type Foo <: {def foo(): Unit} is type Foo <: AnyRef{def foo(): Unit}.

So while type Bar <: {def bar(): Unit} with Foo is not parsable, with AnyRef and different order it works

type Foo <: {def foo(): Unit}
type Bar <: Foo with AnyRef{def bar(): Unit}

val b: Bar = ???
b.foo()
b.bar()

Also with brackets (and direct order) it works

type Foo <: {def foo(): Unit}
type Bar <: ({def bar(): Unit}) with Foo 

val b: Bar = ???
b.foo()
b.bar()

Actually type Bar <: {def bar(): Unit} with Foo is against the spec while type Bar <: ({def bar(): Unit}) with Foo satisfies the spec because {def bar(): Unit} is not a SimpleType but ({def bar(): Unit}) is a SimpleType.

CompoundType    ::=  AnnotType {‘with’ AnnotType} [Refinement]
                  |  Refinement

AnnotType       ::=  SimpleType {Annotation}

SimpleType      ::= ............
                  |  ‘(’ Types ‘)’

Types           ::=  Type {‘,’ Type}

Type            ::=  ...........
                  |  CompoundType
                  |  ...........

https://scala-lang.org/files/archive/spec/2.13/03-types.html#compound-types

Meadowlark answered 12/9, 2020 at 8:59 Comment(0)
F
9

Seems to work with parenthesis

scala> type Foo <: {def foo(): Unit}
     | type Bar <: ({def bar(): Unit}) with Foo
type Foo
type Bar
Forgiveness answered 12/9, 2020 at 9:27 Comment(0)
M
8

type Foo <: {def foo(): Unit} is type Foo <: AnyRef{def foo(): Unit}.

So while type Bar <: {def bar(): Unit} with Foo is not parsable, with AnyRef and different order it works

type Foo <: {def foo(): Unit}
type Bar <: Foo with AnyRef{def bar(): Unit}

val b: Bar = ???
b.foo()
b.bar()

Also with brackets (and direct order) it works

type Foo <: {def foo(): Unit}
type Bar <: ({def bar(): Unit}) with Foo 

val b: Bar = ???
b.foo()
b.bar()

Actually type Bar <: {def bar(): Unit} with Foo is against the spec while type Bar <: ({def bar(): Unit}) with Foo satisfies the spec because {def bar(): Unit} is not a SimpleType but ({def bar(): Unit}) is a SimpleType.

CompoundType    ::=  AnnotType {‘with’ AnnotType} [Refinement]
                  |  Refinement

AnnotType       ::=  SimpleType {Annotation}

SimpleType      ::= ............
                  |  ‘(’ Types ‘)’

Types           ::=  Type {‘,’ Type}

Type            ::=  ...........
                  |  CompoundType
                  |  ...........

https://scala-lang.org/files/archive/spec/2.13/03-types.html#compound-types

Meadowlark answered 12/9, 2020 at 8:59 Comment(0)
H
4

It's not allowed by the spec, which calls the { ...} part a refinement which may both have a with clause. The other way around it's fine though.

That's somewhat tautological of course as it doesn't say why it's not allowed by the spec. It appears there is no deep understanding here, just that that's not a way you're allowed to write a type. You should be able to express the same intent in another way.

Huckaby answered 12/9, 2020 at 9:32 Comment(6)
Why do you think it's not allowed by the spec? scala-lang.org/files/archive/spec/2.13/… CompoundType ::= AnnotType {‘with’ AnnotType} [Refinement] | Refinement. Here {def bar(): Unit} and Foo are AnnotTypes, Refinement is empty.Meadowlark
@DmytroMitin AnnotType is SimpleType {Annotation} but {def bar(): Unit} is not a SimpleTypeHuckaby
Right, {def bar(): Unit} is not a SimpleType but ({def bar(): Unit}) is a SimpleType.Meadowlark
is it though @DmytroMitin? The compiler accepts it as if it is, but I can't figure out how that works from the specHuckaby
Yes. SimpleType ::= SimpleType TypeArgs | SimpleType ‘#’ id | StableId | Path ‘.’ ‘type’ | Literal | ‘(’ Types ‘)’. Important is the last part, if you surround Types with brackets then you get a SimpleType. Types ::= Type {‘,’ Type}, so one Type is also Types. {def bar(): Unit} is a Type (actually a CompoundType consisting of single Refinement), so ({def bar(): Unit}) is a SimpleType.Meadowlark
Ah, yes, there it is.Huckaby

© 2022 - 2024 — McMap. All rights reserved.