Interfaces
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.