Adding an operator to return the "lowest common type" of two types?


(William Shipley) #1

The problem I’m trying to solve is if I have

class LineSegmentObject {
...
}
class Wall : LineSegmentObject {
...
}
class Ray : LineSegmentObject {

}

And then in my code if I have

        let wallsInBounds: Set<Wall> = …
        let raysOffWalls: Set<Ray> = ...

        let unionOfAllTestedLineSegmentObjects = wallsInBounds.union(raysOffWalls)

it fails to compile. Instead I have to do the very ugly

        var unionOfAllTestedLineSegmentObjects: Set<LineSegmentObject> = (raysOffWalls as Set<LineSegmentObject>).union(wallsInBounds as Set<LineSegmentObject>)

As an aside, this also fails, surprisingly to me:

        var unionOfAllTestedLineSegmentObjects = Set<LineSegmentObject>()
        unionOfAllTestedLineSegmentObjects.unionInPlace(wallsInBounds)

···

So, what if we had an operator called, say, “commonType” that could take two types and return the closest type the both have in common?

Then the union operator for Set (and similar operators in Array and Dictionary) could look something like:

    public func union<S : SequenceType>(sequence: S) -> Set<commonType(Element, S.Generator.Element)>

instead of:

    public func union<S : SequenceType where S.Generator.Element == Element>(sequence: S) -> Set<Element>

[sorry if I got the syntax of defining a generic wrong up there, I’m still new to this)

So we’d automatically get an Set of LineSegments if we union a Set of Rays with a Set of Walls, which is what I’d expect.

If this type of thing doesn’t seem strict enough for you, then it could also just be a separate function, like “heterogenousUnion()” instead of “union()”.

Also, I believe this could make it a LOT easier to build heterogenous Dictionaries in code, which I actually can’t do at all in the current Swift. (Eg, creating dictionaries with arbitrary types of keys and values that you might feed to, say, SCNTechnique.) And it’d make dealing with mixed Arrays easier in a similar way.

--

On a scale from “Lattner" to “Lohan,” how bad an idea is this?

-Wil


(Jon Hull) #2

I like it.

This was actually one of the first problems I ran into when I first tried swift.

I would really like to see syntax like ‘TypeA | TypeB’ meaning the type could be either ‘TypeA' or ‘TypeB’. You should be able to call any functions/methods which are common to both types without having to cast.

As you say, the result of union (or similar collection building methods) should be the intersection of the types together in the collection (and I believe the above idea would give the type system a concrete way to reason about that). So in your case unionOfAllTestedLineSegmentObjects would have type Set<Wall | Ray>. ‘Wall | Ray’ would essentially be the same as LineSegmentObject, but might also have extra methods available (e.g. say they both ended up conforming to a protocol which LineSegmentObject doesn’t).

  public func union<S : SequenceType>(sequence: S) -> Set<Element | S.Generator.Element>

I could also explicitly build an array of type [String | Int] where in some cases I care about which one it is (and thus cast with is or as? to find out), and in other cases I don’t, and just call something they have in common (e.g. comparable)

The biggest win would be for things like JSON, where there are an exact number of very different types allowed. Currently we have to use ‘Any’ to represent that mix of types, but with the above idea, we could represent that requirement exactly.

It allows us to have much more fluidity (something closer to duck-typing) while still keeping full type safety.

I do realize that is a large ask though, since it involves the type system...

Thanks,
Jon

···

On Dec 7, 2015, at 1:53 AM, William Shipley via swift-evolution <swift-evolution@swift.org> wrote:

The problem I’m trying to solve is if I have

class LineSegmentObject {
...
}
class Wall : LineSegmentObject {
...
}
class Ray : LineSegmentObject {

}

And then in my code if I have

        let wallsInBounds: Set<Wall> = …
        let raysOffWalls: Set<Ray> = ...

        let unionOfAllTestedLineSegmentObjects = wallsInBounds.union(raysOffWalls)

it fails to compile. Instead I have to do the very ugly

        var unionOfAllTestedLineSegmentObjects: Set<LineSegmentObject> = (raysOffWalls as Set<LineSegmentObject>).union(wallsInBounds as Set<LineSegmentObject>)

As an aside, this also fails, surprisingly to me:

        var unionOfAllTestedLineSegmentObjects = Set<LineSegmentObject>()
        unionOfAllTestedLineSegmentObjects.unionInPlace(wallsInBounds)

So, what if we had an operator called, say, “commonType” that could take two types and return the closest type the both have in common?

Then the union operator for Set (and similar operators in Array and Dictionary) could look something like:

    public func union<S : SequenceType>(sequence: S) -> Set<commonType(Element, S.Generator.Element)>

instead of:

    public func union<S : SequenceType where S.Generator.Element == Element>(sequence: S) -> Set<Element>

[sorry if I got the syntax of defining a generic wrong up there, I’m still new to this)

So we’d automatically get an Set of LineSegments if we union a Set of Rays with a Set of Walls, which is what I’d expect.

If this type of thing doesn’t seem strict enough for you, then it could also just be a separate function, like “heterogenousUnion()” instead of “union()”.

Also, I believe this could make it a LOT easier to build heterogenous Dictionaries in code, which I actually can’t do at all in the current Swift. (Eg, creating dictionaries with arbitrary types of keys and values that you might feed to, say, SCNTechnique.) And it’d make dealing with mixed Arrays easier in a similar way.

--

On a scale from “Lattner" to “Lohan,” how bad an idea is this?

-Wil

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Martin Kühl) #3

The problem I’m trying to solve is if I have

class LineSegmentObject {
...
}
class Wall : LineSegmentObject {
...
}
class Ray : LineSegmentObject {

}

And then in my code if I have

        let wallsInBounds: Set<Wall> = …
        let raysOffWalls: Set<Ray> = ...

        let unionOfAllTestedLineSegmentObjects =
wallsInBounds.union(raysOffWalls)

it fails to compile. Instead I have to do the very ugly

        var unionOfAllTestedLineSegmentObjects: Set<LineSegmentObject> =
(raysOffWalls as Set<LineSegmentObject>).union(wallsInBounds as Set<
>)

As an aside, this also fails, surprisingly to me:

        var unionOfAllTestedLineSegmentObjects = Set<LineSegmentObject>()
        unionOfAllTestedLineSegmentObjects.unionInPlace(wallsInBounds)

So, what if we had an operator called, say, “commonType” that could take
two types and return the closest type the both have in common?

Then the union operator for Set (and similar operators in Array and
Dictionary) could look something like:

    public func union<S : SequenceType>(sequence: S) -> Set<commonType(Element,
S.Generator.Element)>

instead of:

    public func union<S : SequenceType where S.Generator.Element ==
>(sequence: S) -> Set<Element>

[sorry if I got the syntax of defining a generic wrong up there, I’m still
new to this)

So we’d automatically get an Set of LineSegments if we union a Set of Rays
with a Set of Walls, which is what I’d expect.

I think I like the idea, but I don’t think we should need a dedicated
operator for this.
How do you feel about a declaration like this:

    func union<S: SequenceType, E where Element: E, S.Generator.Element:

(sequence: S) -> Set<E>

Martin

···

On 7 December 2015 at 10:53, William Shipley via swift-evolution < swift-evolution@swift.org> wrote:

If this type of thing doesn’t seem strict enough for you, then it could
also just be a separate function, like “heterogenousUnion()” instead of
“union()”.

Also, I believe this could make it a LOT easier to build heterogenous
Dictionaries in code, which I actually can’t do at all in the current
Swift. (Eg, creating dictionaries with arbitrary types of keys and values
that you might feed to, say, SCNTechnique.) And it’d make dealing with
mixed Arrays easier in a similar way.

--

On a scale from “Lattner" to “Lohan,” how bad an idea is this?

-Wil


(thorsten@portableinnovations.de) #4

Seems like you want union types (like I do!). Ceylon has great support for union and intersection types and they really shine there!

See http://ceylon-lang.org/documentation/1.2/tour/types/
and the Talk by Gavin King http://ceylon-lang.org/community/presentations/eight-ceylon-idioms.pdf

I'd love to see support for this in Swift.

-Thorsten

···

Am 07.12.2015 um 10:53 schrieb William Shipley via swift-evolution <swift-evolution@swift.org>:

The problem I’m trying to solve is if I have

class LineSegmentObject {
...
}
class Wall : LineSegmentObject {
...
}
class Ray : LineSegmentObject {

}

And then in my code if I have

        let wallsInBounds: Set<Wall> = …
        let raysOffWalls: Set<Ray> = ...

        let unionOfAllTestedLineSegmentObjects = wallsInBounds.union(raysOffWalls)

it fails to compile. Instead I have to do the very ugly

        var unionOfAllTestedLineSegmentObjects: Set<LineSegmentObject> = (raysOffWalls as Set<LineSegmentObject>).union(wallsInBounds as Set<LineSegmentObject>)

As an aside, this also fails, surprisingly to me:

        var unionOfAllTestedLineSegmentObjects = Set<LineSegmentObject>()
        unionOfAllTestedLineSegmentObjects.unionInPlace(wallsInBounds)

So, what if we had an operator called, say, “commonType” that could take two types and return the closest type the both have in common?

Then the union operator for Set (and similar operators in Array and Dictionary) could look something like:

    public func union<S : SequenceType>(sequence: S) -> Set<commonType(Element, S.Generator.Element)>

instead of:

    public func union<S : SequenceType where S.Generator.Element == Element>(sequence: S) -> Set<Element>

[sorry if I got the syntax of defining a generic wrong up there, I’m still new to this)

So we’d automatically get an Set of LineSegments if we union a Set of Rays with a Set of Walls, which is what I’d expect.

If this type of thing doesn’t seem strict enough for you, then it could also just be a separate function, like “heterogenousUnion()” instead of “union()”.

Also, I believe this could make it a LOT easier to build heterogenous Dictionaries in code, which I actually can’t do at all in the current Swift. (Eg, creating dictionaries with arbitrary types of keys and values that you might feed to, say, SCNTechnique.) And it’d make dealing with mixed Arrays easier in a similar way.

--

On a scale from “Lattner" to “Lohan,” how bad an idea is this?

-Wil

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution