One issue here is that there is not only one kind of type conversion.
If I understand your point correctly, you’re proposing that there is a category of operations called “type conversion” and that all members of this category should behave the same – to homogenize.
But I think the category “type conversion” is itself heterogeneous. For instance, type conversion may be divided into “if-necessary” conversion (where the conversion method prefers to return the receiver if that’s appropriate) and “forced” conversion (always create and return a new object based on the receiver).
In general, method names of the format asSomething
are if-necessary, while as(Something)
is “forced” (since it’s a synonym for Something.newFrom(x)
).
The argument seems to be that the two syntaxes asSomething
and as(Something)
are very similar, so they should be unified. But they mean different things. You can’t unify operations that are not the same.
A possible solution here would be to remove as(Something)
and require users always to write Something.newFrom(x)
, and reserve asXXX
for the if-necessary case – that is, to make the syntax more divergent for different operations. This also makes the problem with as(Integer)
explicit – because there is no concept of a “new” Integer (or any atomic type). I guess the best you could do is:
+ Integer {
*newFrom { |x| ^x.asInteger }
}
… but I can easily imagine someone reading this and thinking “what-the-xxxx is that for?” … and there would be no point anyway to writing Integer.newFrom(aNumber)
vs aNumber.asInteger
.
I think this can be explained as a case of multichannel expansion. Many places in SC accept either a single number or an array of numbers (multichannel expansion), so it isn’t completely outrageous for numeric type conversion to multichannel-expand also.
Consider this:
f = { |numberOrArrayOfNumbers|
// now I want all of them to be floats
if(numberOrArrayOfNumbers.isArray) {
numberOrArrayOfNumbers = numberOrArrayOfNumbers.collect(_.asFloat);
} {
numberOrArrayOfNumbers = numberOrArrayOfNumbers.asFloat;
};
... etc...
};
I don’t think anybody really wants to be forced to do that… but if asFloat
didn’t multichannel expand, this is what everyone would have to do.
Fully agreed – Array2D is not a useful class. We should deprecate it.
It’s a worthy goal to address sources of confusion. But, I’m skeptical of the idea that a confusing area in a programming language is necessarily the fault of the language. (For instance, multichannel expansion of numeric type conversion is a little confusing, but it’s also very useful! And, consistent with other idioms in SC.)
Programming language acquisition mirrors natural language acquisition. A child learning English might say “dad goed to the store” and then find out that the general rule “-ed = past tense” doesn’t apply to all verbs. Similarly, when encountering asArray
and as(Array)
, it’s understandable to overgeneralize and collapse them into one category – but they don’t actually belong to one category. This process of overgeneralizing and then refining distinctions is a natural part of learning programming. (The opposite process – undergeneralizing and gradually coming to understand a more general principle – is another natural part of it.)
There is a temptation to say “if I have to refine my understanding, then something is badly designed in the language” but this may not always be true (or, redesigning might introduce different confusion). Lately I notice this kind of thinking in myself (“I’ve been doing this a long time, I know what I’m doing, I shouldn’t suffer confusion so it’s the software’s fault” ) and I’m working at recognizing it and questioning whether design could really have avoided confusion.
With that said, it might actually be a good idea to get rid of as(aClass)
– another case of syntax sugar sometimes backfiring.
hjh