Comments intermingled.

> One point I would like to make here is that not all downcasting is due
> to co-/contra-variance issues.  Consider the situation where you have
> a "number" that contains the member add.  Now, it makes sense to add
> two reals together (I'll grant you that all reals are in some sense
> fungible, even though this leads to unexpected code behavior), and it
> makes sense to add two vectors together, but it doesn't make sense to
> add a real to a vector, either mathematically or programmatically.
> And it makes sense to define algorithms which work on
> sets/lists/arrays of reals and sets of vectors, but not on mixed sets
> of reals and vectors.  So how do you define this constraint in the
> type system?
>

Define a function that takes a list of reals, define a function that
takes a list of vectors, and don't define a function that takes a list
of (real|vector)s. I don't see the problem here.

>> let xys = x :: y :: [x]
>>
>> Then the types are all well-defined: list of things like x, list of
>> things like y, list of things like x-or-y.  You can't turn "xys" into
>> a list of xs or a list of ys, because it's neither.
>>
>
> And what can I say about an element I've taken off a list of x-or-ys,
> say by using List.head?
>
It's of type x|y, whose API is the intersection of the API of x and y.
If you want to find out if it is an x or a y, use a match.

> In this example, both x and y have a common supertype, the type of
> objects with an add function.
>
>> The only place where I've found subtyping issues is with code like this:
>>
>> let foundXs = xys.findAll { it -> it.like(x) }
>> (Where "like" is "structurally identical to".)
>>
>> The list "foundXs" is now a list of "x"-like structures, even though
>> the type is a list of "x-or-y"-like structures.  But that—like a
>> couple of the similar cases I've encountered—are what *should be*
>> match statements being dropped in strange places, usually because of
>> an OOP accent in the programmer.  And it's easy to define a
>> properly-typed findAllLike, if you really wanted to stick to it:
>>
>> let findAllLike = {list,type -> list match {
>>  case () => ()
>>  case (a:type) :: rest => a::findAllLike(rest, type)
>>  case a::rest => findAllLike(rest)
>> }}
>>
>
> Congratulations, you've reinvented Java's instanceof.
>
Yes: my point is that such code is the only place I'm thinking of
where I regularly encounter having to downcast in other languages
(modulo hacking around Java's generics), but it's actually able to be
handled just fine in the type system if you prevent forced casts.

>> So it doesn't seem to be a problem to reject importing the idea of
>> "casting up", which is good since it doesn't even really mean anything
>> anyway in this context.
>
> Except you have up casted- take a look at that middle case there.
>
I should have prefixed it with "unsafe casting up", or "forced casting
up", or whatever.  The maneuver equivalent to "(Foo)foo" in Java,
where you are telling the program, "I know more about this type than
you do, so just trust me, it's a Foo."  I'm trying to figure out where
this is such a nightmare that I should run screaming from having any
kind of type hierarchy. I'm inclined to just straight up say you can't
force casts.

~~ Robert.

-- 
You received this message because you are subscribed to the Google Groups "JVM 
Languages" group.
To post to this group, send email to jvm-languages@googlegroups.com.
To unsubscribe from this group, send email to 
jvm-languages+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/jvm-languages?hl=en.

Reply via email to