views:

106

answers:

6

I like reading about programming theories, so could you tell me if there is any object-oriented static typed language that allow variables to have a few types? Example in pesudocode:

var value: BigInteger | Double | Nil

I think about way of calling methods on this object. If object value have type BigInteger | Double language could allow user to call only shared methods (lake plus, minus) but when the type is BigInteger | Double | Nil then object of Nil hasn't methods plus and minus, so we can't do anything usefull with this object, because it has only few shared methods (like toString).

So is there any idea how should work calling methods on variable with few types in static typed object-oriented language?

A: 

It has not much to do with OO but (as far as I understand it) what you describe looks much like polymorphism as implemented by C++.

kriss
A: 

I'm not so sure if we really have a complete definition of what a static typed language is but I also hope that the language you describe wouldn't qualify as one.

One of my concerns is that if you add type T1 and T2 to be a part of your BigInteger | Double | Nil, how would they know about each other and how to handle the operations you defined? Now I realize you never said that the language would allow expanding the "implicit" conversion definition.

Come to think of it, C# does something that resembles this in its string handling

string s = -42 + '+' + "+" + -0.1 / -0.1 + "=" + (7 ^ 5) + 
  " is " + true + " and not " + AddressFamily.Unknown; 

=> "1+1=2 is True and not Unknown"

string str = 1 + 2 + "!=" + 1 + 2;

=> "3!=12"

And I do not like it.

Jonas Elfström
+3  A: 

I am not aware of any language that does this... sadly, I'd love to play around with it (but first, they should adopt type inference and parametric polymorphism ;) ).

Although it is alreapossible: Relatively elegantly in a structural type system (type a is a subtype of type b if a has everything b has), simply by specifying a type for value that is a structural subtype of BigInteger and of Double and of Nil and slightly less elegantly in a nominative type system (type a is a subtype of type b if and only if it inherits from it, directly or indirectly) by specifying a common ancestor of all three (if all else fails, object). Of course we'd need to go recursive - what is the type of toString? And what's the typ of (Integer | Double | BigInteger).+?!? This is far from trivial (in fact, looking for a solution made my head hurt a bit). I can't say if it is impossible, but no mainly-OO-language's type system is anywhere sophisticated enough for a possible solution.

The bottom line is: It'd be really cool if some whizz came along and sorted out the issues it raises. Propably not worth the effort...

Edit: Do you know algebraic data types? They are similar to your idea (but much older ;) ) in that an algebraic data type is composed of several types and can therefore contain e.g. a BigInteger, a Double and Nil - the actual value is one of these and a tag (as in tagged union) says which. But to use the value stored in an algebraic data type, you have to use pattern matching to extract it safely. This concept is very powerful, and still "simple" enough to be understood tools - e.g. type inference and static typechecking work.

delnan
I'd really like the down voter to explain why because I like this reasoning.
Jonas Elfström
+6  A: 

What you are describing is an intersection type. They do exist in Java, for example, but they only arise within the type-checker as the result of capture conversion and type-inference. You cannot write one yourself.

I don't know of any language which uses them directly, but they are often used to describe or analyze type systems of languages, espececially languages which don't actually have a type system. For example, Diamondback Ruby, which is a static type system and type-inferencer for the dynamically typed Ruby programming language, uses both union and intersection types.

Note that the syntax you are using is generally used to denote union types, which are the dual of intersection types. Intersection types are generally written A & B & C.

Jörg W Mittag
C# effectively has intersection types in its `where` constraints for generic type parameters. If you define a type parameter with the constraint `where T : IFoo, IBar` then within the body of that method, `T`'s static type is the intersection of `IFoo` and `IBar`.
munificent
A: 

Yes, OCaml has these in the form of polymorphic variants:

type my_var = Integer of int | Float of float;;
let x = Integer(10);;
let y = Float(3.14);;
Niki Yoshiuchi
What you're showing is an union type. What OP is asking about is called intersection type.
missingfaktor
It's not even a plain union, it's a tagged union aka discriminated union aka algebraic data type.
delnan
A: 

Pike has them, as does Magpie, an optionally-typed language I'm working on. Google's Closure compiler for Javascript allows you to annotate types in Javascript using |.

They crop up frequently in languages that bridge static and dynamic typing because a lot of expressions in a dynamic language can yield one of a couple of types:

var a = 123;
if (foo) { a = "string"; }
bar(a);

The statically-determined type being passed to bar() is Number | String.

munificent
The OP describes an intersection type but Pike "only" has tagged/discriminated unions (unless wiki lies to me) and same goes for magpie.
delnan
The original post isn't very clear, but I believe he is talking about union types. If you have a variable of union type `Foo | Bar`, the only allowed operations on it are ones common to *both* `Foo` and `Bar`. It's a "union" because any value of type `Foo` *or* `Bar` is a valid member of the type. In other words, a union type is wide in the values it accepts but narrow in the operations you can perform on them.
munificent
An intersection type (which Magpie will likely have at some point) is the opposite: narrow in the values it accepts, but wide in the operations it supports. A practical example is `where` constraints in C#. If you give a type parameter a constraint like `IFoo, IBar`, it means only types that implement *both* of those interfaces are valid. Given a variable of that type, you can then call a method on it if the method is defined in *any* of the listed interfaces.
munificent