Interfaces

From Adam Colton
Jump to navigation Jump to search

This is one of the areas with the largest difference from Go.

Built In and Operators

The built in types will have methods. The operators are defined as methods. This means that you can define interfaces that will include the built in types.

See Operator Methods

Unions

This is a tagged union, like the Enum from Rust

 type IntN union [
   int8
   int16
   int32
   int64
 ]

What makes it an interface is that any method shared by all members is a method on the union.

 var i IntN = Foo()
 if i.int8? {
   // in this block i has type int8
 }
 select i{ // select, not switch
   case int8:
     // in this block i also has type int8
 }

If you union a union, the result can be have a nested union, but also behaves as the composite.

 type Foo union[
   Null
   Foo
   FooError
 ]
 type Bar union[
   Null
   Bar
   BarError
 ]
 type FooBar union[
   Foo
   Bar
 ]

FooBar can be checked against Foo or Bar, but it can also be checked against Null and that will take up only a single tag regardless of if that is Foo.Null or Bar.Null.

Coercion

Not sure about this, but I would like returns on concretes to be coerced to more general types and arguments to be coerced to more specific types. So

 func Foo(s *MyStringer) IFooer

on an interface would match

 func Foo(s Stringer) Foo

on a concrete.

However, I think the syntax should be explicit to allow coercion, so maybe

 func Foo(s <*MyStringer>) <IFooer>

or

 func Foo(s ~*MyStringer) ~IFooer

One of the cases where I want this is for graph structures.

 type BinaryTreeNode <
   elem interface{
     <Less(elem) bool
   }
 >interface{
   Parent() Null<BinaryTreeNode>
   Left() Null<BinaryTreeNode>
   Right() Null<BinaryTreeNode>
   Value() elem
   mut Insert(elem)
 }

Substitution (Generics)

When defining a type, an interface signature can be provided for substitution

 type MyMap <
   Elem Stringer
 > map[string]Elem
 
 func (MyMap) New() *MyMap{
   return make(MyMap)
 }
 
 func (m *MyMap) Add(e Elem){
   m[e.String()]=e
 }
 
 func (m MyMap) Get(str string) (Elem, bool){
   return m[str]
 }

This could now be called as:

 mStr := MyMap<Elem:string>.New()
 mFoo := MyMap<Elem:Foo>.New()
 mStr = mFoo // error, types do not match
 baseM := MyMap<Elem:Stringer>.New()
 baseM = MyMap<Elem:Stringer>(mStr) // can't actually do this because you can't convert Add(e string) to Add(e Stringer)

Packages

I've always liked this idea - packages tend to behave like types. Functions in the package behave like methods. So packages should be able to fulfill interfaces.

Derived

This may be syntactic sugar. Often there is an interface that is only meant to represent a single type. Or there is one type that is considered the standard and a number of types that are meant to align with it. It would be useful to have a way to do this without redefining a bunch of methods.

 type Fooer interface Foo

would mean that Fooer has all the public methods that Foo has.

As TypeSets

To abstract away this whole thing, we could have a single abstraction of a TypeSet. A type set can answer compile-time questions about membership.

  • Is type A a member of typeset X
  • Is method M defined on typeset X

And a typeset is itself a type and so we can ask if typeset A is a member of typeset B.