Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Polymorphism #7

Open
phase opened this issue Dec 30, 2016 · 5 comments
Open

Polymorphism #7

phase opened this issue Dec 30, 2016 · 5 comments
Labels

Comments

@phase
Copy link
Owner

phase commented Dec 30, 2016

When designing polymorphism, we need to take the LLVM backend into account, as it is the main backend (and currently the only one that exists).

Inheritance subtype polymorphism

Here is some example syntax for how I want to do this.

class A
    let a : Int32
;

class B : A
    let b : Int32
;

initB () : B
    let b = new B(),
    b.a = 7,
    b.b = 8,
    b

Classes in the AST will hold one parent Class.

class Clazz(val parent : Clazz, ...)

This will create two types in IR. There are two different ways to express these types.

%A = type { i32 }
%B = type { i32, i32 }
%A = type { i32 }
%B = type { %A*, i32 }

The second way poses a problem: Is %A* the parent class or a field? With the first way, we know every element in the type is a field, with some of them coming from the parent class.

Generics parametric polymorphism

Generics are a great for code reuse and other stuff, so here are some designs for them.

class Box<T>
    let value : T
;

main ()
    let boxInt32 = new Box<Int32>(),
    boxInt32.value = 32,
    let boxInt64 = new Box<Int64>(),
    boxInt64.value = 64l,
    0

Generics can be stored inside the Type class.

class Type(val generics : List<Type> = listOf(), ...)

Only the needed types will be generated.

%Box_Int32 = type { i32 }
%Box_Int64 = type { i64 }

These will be generated in the getLLVMType function. When parsing, we need to send the generic types in the current Class to getType. Then we can check if the fields of a Class are one of the generic types.

@phase phase added the desgin label Dec 30, 2016
@phase
Copy link
Owner Author

phase commented Dec 30, 2016

Ugh. I attempted generics in a238a0c, but it went downhill quickly. I think restarting it after I plan it out a little will be better. Class generation went the same way.

@phase
Copy link
Owner Author

phase commented Jan 15, 2017

Inheritence: Embedded Fields

Classes can have multiple parents.

class W
    let w = 0
;

class A : W
    let a = 0
;

class B : W
    let b = 0
;

class C : A, B
    let c = 0
;

These will create IR types with the fields embedded in them.

%W = type { i32 }

%A = type {
    i32, ; w from W
    i32  ; a from A
}

%B = type {
    i32, ; w from W
    i32  ; b from B
}

%C = type {
    i32, ; w from W
    i32, ; a from A
    i32, ; b from B
    i32  ; c from C
}

We can then bitcast types to their parents.

; Assume this function modifies the fields in A
declare void something(%W*)

define void something_calling_something(%C*) {
    %C_as_W = bitcast %C* %0 to %W*
    ; This will treat the beginning bits as W's fields
    call void @something(%W* %C_as_W)
    ret void
}

Where does this go horribly wrong? Downcasting. What happens when we cast a %C* to a %B*?

define void wrong(%C*) {
    %C_as_B = bitcast %C* %0 to %B*
}

What's going on in the memory?

%C = type {
    i32, ; w from W
    i32, ; a from A
    i32, ; b from B ; This is the third field
    i32  ; c from C
}

%B = type {
    i32, ; w from W
    i32  ; b from B - This is the second field
}

%C_as_B = type {
    i32, ; w from W
    i32  ; a from A - Oh shit
}

The fields of B are offset because we needed to make room for A's fields. This version of storing fields doesn't work for multiple parents.

@phase
Copy link
Owner Author

phase commented Jan 15, 2017

Another thing that needs to be figured out is calling an overridden method. If B overrides a method in A, and we have an instance of A that was downcasted from B, how do we know which method implementation to call?

This should be done in Type Checking (leaving this here because this thought has come to my mind more than once and I keep forgetting the solution).

@phase
Copy link
Owner Author

phase commented Feb 23, 2017

Types dependent on values and types can be used to define Integer types with variable bits or Arrays with a fixed size.

// identifier -> generic type
// a : b -> value of type b
class Array<T, size : T>

class Int<size : Int8>

This could be used for internal types, but user defined types wouldn't have much of a use because you coud easily pass in a parameter to the constructor.

let a = new Int(29, 7)

This could create a new Int29 with a value of 7.

@phase
Copy link
Owner Author

phase commented Mar 22, 2017

Single inheritence solves the downcasting problem.

Interfaces/Traits are another thing to be added, prefering the latter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant