To achieve maximum levels of freedom and expressiveness, Luna allows calling methods on polymorphic arguments. Of course it's not always possible to infer what is the result type, so in this case we leave this unsolved until the real type is really needed. If you're familiar with the "duck typing" technique from dynamic languages, it's exactly the same in Luna, except when it's not really possible to call the function, you still get a compile-time error. Consider the following function:

def callSucc a: a.succ

What is its type? Since we haven't defined what is the type of `a`

, we are assigning it a type parameter `b`

. Now, what is the type of method `succ`

on a type `b`

? We can never know, as it depends on the implementation of a particular class that will be used. Hence, the type of `callSucc`

is simply `b -> b.succ`

. You can read it as "a function that takes an argument of type `b`

and returns whatever the method `succ`

of class `b`

returns". We can now write `callSucc 1`

, since the `succ`

method is defined for `Int`

s, but `callSucc "hello"`

will result in a compile error.

Luna's typechecker stores some additional assumptions about type parameters, that need to be met by the types substituted for the variables. Those usually arise from manually typed functions and using methods on polymorphic values. Let's start with a simple example. The `+`

operator is defined in Luna standard library as:

def + :: a -> a -> adef + x y = x.+ y

This definition allows us to write expressions like `5 + 7`

or `"foo" + "bar"`

, but will reject `"foo" + 5`

(because arguments' types are different) or `Just 5 + Just 7`

(because the `+`

method is not defined for the `Maybe`

class). So what is really going on here?

First of all, the user-specified type indicates that both the arguments and the return type need to be of the same type. Second, the use of the method `+`

indicates that the type `a`

needs to have this method defined. Moreover, this method needs to take a single argument of type `a`

and return a result also of type `a`

. All this allows us to describe the type of function `+`

as:

+ :: a -> a -> a

for any `a`

such that `a.+ = a -> a`

All this is handled by the Luna compiler under the hood, so that you don't need to think about all the assumptions present.

Let's consider another example:

`def foo x: x.succ + 1`

What is the type of this function? First of all, we can see that the result of `x.succ`

is added to an `Int`

, so (from the definition of `+`

above) we know that `x.succ :: Int`

and that the result of this function is also an `Int`

. So the final type with the underlying assumptions is:

foo :: a -> Int

for any `a`

such that `a.succ = Int`

All those assumptions can grow with more complex, multiline functions. That's why Luna tracks them under the hood, revealing them only when some of them can't be satisfied.