Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Initial note:

This question got closed after several edits because I lacked the proper terminology to state accurately what I was looking for. Sam Tobin-Hochstadt then posted a comment which made me recognise exactly what that was: programming languages that support intersection types for function return values.

Now that the question has been re-opened, I've decided to improve it by rewriting it in a (hopefully) more precise manner. Therefore, some answers and comments below might no longer make sense because they refer to previous edits. (Please see the question's edit history in such cases.)

Are there any popular statically & strongly typed programming languages (such as Haskell, generic Java, C#, F#, etc.) that support intersection types for function return values? If so, which, and how?

(If I'm honest, I would really love to see someone demonstrate a way how to express intersection types in a mainstream language such as C# or Java.)

I'll give a quick example of what intersection types might look like, using some pseudocode similar to C#:

interface IX { … }
interface IY { … }
interface IB { … }

class A : IX, IY { … }
class B : IX, IY, IB { … }

T fn()  where T : IX, IY
{
    return … ? new A()  
             : new B();
}

That is, the function fn returns an instance of some type T, of which the caller knows only that it implements interfaces IX and IY. (That is, unlike with generics, the caller doesn't get to choose the concrete type of T — the function does. From this I would suppose that T is in fact not a universal type, but an existential type.)

P.S.: I'm aware that one could simply define a interface IXY : IX, IY and change the return type of fn to IXY. However, that is not really the same thing, because often you cannot bolt on an additional interface IXY to a previously defined type A which only implements IX and IY separately.


Footnote: Some resources about intersection types:

Wikipedia article for "Type system" has a subsection about intersection types.

Report by Benjamin C. Pierce (1991), "Programming With Intersection Types, Union Types, and Polymorphism"

David P. Cunningham (2005), "Intersection types in practice", which contains a case study about the Forsythe language, which is mentioned in the Wikipedia article.

A Stack Overflow question, "Union types and intersection types" which got several good answers, among them this one which gives a pseudocode example of intersection types similar to mine above.

share|improve this question
6  
How is this ambiguous? T defines a type, even if it's just defined within the function declaration as "some type that extends/implements IX and IY". The fact that the actual return value is a special case of that (A or B respectively) isn't anything special here, you could just as well achieve that by using Object instead of T. –  Joachim Sauer Feb 24 '12 at 11:15
1  
Ruby allows you to return whatever you want from a function. Same for other dynamic languages. –  thorsten müller Feb 24 '12 at 11:22
    
I've updated my answer. @Joachim: I'm aware that the term "ambigous" doesn't capture the concept in question very accurately, thus the example to clarify the intended meaning. –  stakx Feb 24 '12 at 12:31
1  
Ad P.S.: ... which changes your question to "which language allows treating type T as interface I when it implements all methods of the interface, but did not declare that interface". –  Jan Hudec Feb 24 '12 at 12:38
4  
It was a mistake to close this question, because there's a precise answer, which is union types. Union types are available in languages such as (Typed Racket)[docs.racket-lang.org/ts-guide/]. –  Sam Tobin-Hochstadt Feb 24 '12 at 16:35

7 Answers 7

up vote 4 down vote accepted

In fact, the obvious answer is: Java

Whilst it may surprise you to learn that Java supports intersection types ... it does indeed through the "&" type bound operator. For example:

<T extends IX & IY> T f() { ... }

See this link on multiple type bounds in Java, and also this from the Java API.

share|improve this answer
    
Will that work if you don't know the type at compile time? I.e. can one write <T extends IX & IY> T f() { if(condition) return new A(); else return new B(); }. And how do you call the function in such case? Neither A nor B can appear at the call site, because you don't know which one you'll get. –  Jan Hudec Oct 18 '12 at 9:07
    
Yes, you're right --- its not equivalent to the original example given since you do need to provide a concrete type. If we could use wildcards with intersection bounds, then we'd have it. Seems like we can't ... and I don't really know why not (see this). But, still Java does have intersection types of a sort ... –  redjamjar Oct 19 '12 at 9:08
    
This is amazing! I am constantly surprised just how fine Java generics were made. –  stakx Aug 11 at 6:55

Original question asked for "ambiguous type". For that the answer was:

Ambiguous type, obviously none. The caller needs to know what they'll get, so it's isn't possible. All any language can return is either base type, interface (possibly auto-generated as in intersection type) or dynamic type (and dynamic type is basically just type with by-name call, get and set methods).

Inferred interface:

So basically you want it to return an interface IXY that derives IX and IY though that interface was not declared in either A or B, possibly because wasn't declared when those types were defined. In that case:

  • Any that is dynamically typed, obviously.
  • I don't remember any statically typed mainstream language would be able to generate the interface (it is the union type of A and B or intersection type of IX and IY) itself.
  • GO, because it's classes implement interface if they have the correct methods, without ever declaring them. So you just declare an interface that derives the two there and return it.
  • Obviously any other language where type can be defined to implement interface outside of definition of that type, but I don't think I remember any other than GO.
  • It's not possible in any type where implementing an interface has to be defined in the type definition itself. You can however work around in most of them by defining wrapper that implements the two interfaces and delegates all methods to a wrapped object.

P.S. A strongly typed language is one in which an object of given type can't be treated as object of another type, while weakly typed language is one that has a reinterpret cast. Thus all dynamically typed languages are strongly typed, while weakly typed languages are assembly, C and C++, all three being typed statically.

share|improve this answer
    
This is not correct there is nothing ambiguous about the type. A language can return so-called "intersection types" --- it's just that few if any mainstream languages do so. –  redjamjar Oct 18 '12 at 1:20
    
@redjamjar: The question had different wording when I answered it and asked for "ambiguous type". That's why it starts with that. The question was significantly rewritten since. I'll expand the answer to mention both the original and the current wording. –  Jan Hudec Oct 18 '12 at 4:56
    
sorry, I missed that obviously! –  redjamjar Oct 18 '12 at 7:20

You might be able to do what you want by using a bounded existential type, which can be encoded in any language with generics and bounded polymorphism, e.g. C#.

The return type will be something like (in psuedo code)

IAB = exists T. T where T : IA, IB

or in C#:

interface IAB<IA, IB>
{
    R Apply<R>(IABFunc<R, IA, IB> f);
}

interface IABFunc<R, IA, IB>
{
    R Apply<T>(T t) where T : IA, IB;
}

class DefaultIAB<T, IA, IB> : IAB<IA, IB> where T : IA, IB 
{
    readonly T t;

    ...

    public R Apply<R>(IABFunc<R, IA, IB> f) {
        return f.Apply<T>(t);
    }
}

Note: I haven't tested this.

The point is that IAB has to be able to apply an IABFunc for any return type R, and an IABFunc has to be able to work on any T which subtypes both IA and IB.

The intent of DefaultIAB is just to wrap an existing T which subtypes IA and IB. Note that this is different from your IAB : IA, IB in that DefaultIAB can always be added to an existing T later on.

References:

share|improve this answer
    
The approach works if one adds a generic object-wrapper type with parameters T, IA , IB, with T constrained to the interfaces, which encapsulates a reference of type T and allows Apply to be invoked upon it. The big problem is that there's no way to use an anonymous function to implement an interface, so constructs like that end up being a real pain to use. –  supercat Jan 28 at 20:51

Scala has full intersection types built into the language:

trait IX {...}
trait IY {...}
trait IB {...}

class A() extends IX with IY {...}

class B() extends IX with IY with IB {...}

def fn(): IX with IY = if (...) new A() else new B()
share|improve this answer

The Go Programming Language kind of has this, but only for interface types.

In Go any type for which the correct methods are defined automatically implements an interface, so the objection in your P.S. doesn't apply. In other words, just create an interface that has all the operations of the interface types to be combined (for which there's a simple syntax) and it all Just Works.

An example:

package intersection

type (
    // The first component type.
    A interface {
        foo() int
    }
    // The second component type.
    B interface {
        bar()
    }

    // The intersection type.
    Intersection interface {
        A
        B
    }
)

// Function accepting an intersection type
func frob(x Intersection) {
    // You can directly call methods defined by A or B on Intersection.
    x.foo()
    x.bar()

    // Conversions work too.
    var a A = x
    var b B = x
    a.foo()
    b.bar()
}

// Syntax for a function returning an intersection type:
// (using an inline type definition to be closer to your suggested syntax)
func frob2() interface { A; B } {
    // return something
}
share|improve this answer

Python

It's very, very strongly typed.

But the type is not declared when a function is created, so the returned objects are "ambiguous".

In your specific question, a better term might be "Polymorphic". That's the common use case in Python is to return variant types which implement a common interface.

def some_function( selector, *args, **kw ):
    if selector == 'this':
        return This( *args, **kw )
    else:
        return That( *args, **kw )

Since Python is strongly typed, the resulting object will be an instance of This or That and cannot (easily) be coerced or cast to another type of object.

share|improve this answer
    
This is quite misleading; while the type of an object is pretty much immutable, values can be converted between types quite easily. To str, for example, trivially. –  James Youngman Feb 25 '12 at 0:29
    
@JamesYoungman: What? That's true for all languages. All languages I've ever seen have to_string conversions left, right and center. I don't get your comment at all. Can you elaborate? –  S.Lott Feb 25 '12 at 12:14
    
I was trying to understand what you meant by "Python is strongly typed". Perhaps I misunderstood what you meant by "strongly typed". Frankly Python has few of the characteristics I would associate with strongly typed languages. For example, it accepts programs in which a function's return type is not compatible with the caller's use of the value. For example, "x, y = F(z)" where F() returns (z,z,z). –  James Youngman Feb 26 '12 at 10:27
    
The type of a Python object cannot (without serious magic) be changed. There is no "cast" operator as there is with Java and C++. That makes each object strongly typed. Variable names and function names have no type binding, but the objects themselves are strongly typed. The key concept here is not the presence of declarations. The key concept is the available of cast operators. Also note that this appears to me to be factual; moderators may dispute that, however. –  S.Lott Feb 26 '12 at 14:56
1  
C and C++ cast operations don't change the type of their operand either. –  James Youngman Feb 27 '12 at 14:23

C++ functions all have a fixed return type, but if they return pointers the pointers can, with restrictions, point to different types.

Example:

class Base {};
class Derived1: public Base {};
class Derived2: public Base{};

Base * function(int derived_type)
{
    if (derived_type == 1)
        return new Derived1;
    else
        return new Derived2;
}

The behavior of the returned pointer will depend on what virtual functions are defined, and you can do a checked downcast with, say,

Base * foo = function(...);dynamic_cast<Derived1>(foo).

That's how polymorphism works in C++.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.