On Sunday, May 25, 2014 2:11:41 PM UTC-7, Adam Smith wrote:
>
> Actually, no. I'm not going to pretend this is a good thing. You're right 
> that it is "consistent and logical" when you're using an academic 
> type-correctness viewpoint. However, it is not consistent from a developer 
> perspective, and here's why.
>
> On most functions, I don't need to specify parametric types (which is 
> good: there is less clutter). Let's say I have a function:
> function output(context::Context, string::String)
>     context.something()
>     println(string)
> end
>
> output(context, "Hi there")
>
> And a few days later I decide it would be better to accept a list of 
> strings instead, so I do the most natural thing, and I just put Vector{} 
> around the type that was already working:
>
> function output(context::Context, strings::Vector{String})
>     context.something()
>     for string in strings println(string) end
> end
>
> output(context, ["Hi there"])
>
> This is absolutely what every new Julia developer will expect to work 
> (regardless of how "correct" it is), and it will fail. It's especially 
> confusing because for some types, it works (like changing Int to 
> Vector{Int}). It is simply bizarre to new developers using the language 
> that the type matching worked on a single element of that type, but not on 
> a parametric collection of that type.
>
> Yes, I know why it is the way it is, and yes, I know why a textbook says 
> it should be this way, but thinking from a UX perspective (where the "user" 
> is a developer new-ish to Julia), it's quite off-putting.
>

It's easier to compose different libraries together when implementers don't 
overtype their methods, and instead rely more on duck typing. To take your 
"output" example, the contract of the vector that's passed in is actually 
only that println needs to be defined on all of its elements, and not that 
every element must be a string.

Suppose for performance reasons I decide to use some more exotic text data 
structure, like a Rope, and for reasons that are out of my control, it 
inherits from FunctionalContainer or something like that instead of from 
String. Julia doesn't have multiple inheritance, so this can easily happen. 
Then if I want to use your library, and you've decided to require a vector 
of String (or out of necessity, some concrete subtype of String), I'm out 
of luck. If you instead define output(context::Context, strings::Vector)then I 
can get on with my business.

For this reason, I think it's better to be sparing with explicit type 
parameters: only add them when you actually want two different method 
bodies depending on the type.

To make this kind of duck typing more explicit and robust, it might be nice 
if Julia eventually added shapes or interfaces or something like that that 
let you specify a little bit more about the contract of arguments in a way 
that depends on what methods are defined on them, but not on their explicit 
type.

Reply via email to