Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

structural type extending another structural type

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().

like image 923
eprst Avatar asked Sep 12 '20 04:09

eprst


People also ask

Can a type extend a type?

Use an intersection type to extend a type in TypeScript, e.g. type TypeB = TypeA & {age: number;} . Intersection types are defined using an ampersand & and are used to combine existing object types. You can use the & operator as many times as necessary to construct a type.

What is meant by structural typing?

A structural type system means that when comparing types, TypeScript only takes into account the members on the type. This is in contrast to nominal type systems, where you could create two types but could not assign them to each other.

Can an interface extend a type TypeScript?

TypeScript allows an interface to extend a class. In this case, the interface inherits the properties and methods of the class. Also, the interface can inherit the private and protected members of the class, not just the public members.

Is duck typing structural?

Duck typing can be viewed as a usage-based structural equivalence between a given object and the requirements of a type.


3 Answers

Seems to work with parenthesis

scala> type Foo <: {def foo(): Unit}
     | type Bar <: ({def bar(): Unit}) with Foo
type Foo
type Bar
like image 80
Mario Galic Avatar answered Oct 11 '22 01:10

Mario Galic


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

like image 32
Dmytro Mitin Avatar answered Oct 11 '22 03:10

Dmytro Mitin


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.

like image 41
Martijn Avatar answered Oct 11 '22 01:10

Martijn