fun sendRequest(url: URL) {}
sendRequest("https://example.com".into())
In case of diamond problem, it could be resolved by explicitly stating the type
interface A
interface B: A
interface C: A
fun SomeClass.into(): B {}
fun SomeClass.into(): C {}
fun foo(a: A) {}
fun main() {
val s: SomeClass
foo(s.into()) // Ambiguity exception
foo(s.into<B>()) // OK
foo(s.into<C>()) // OK
}
Or even allow implicit casting in a block:
fun String.into(): URL {}
fun sendRequest(url: URL) {}
fun main() {
autoConvert(URL::class) {
sendRequest("https://example.com"/*Automatically into'd into URL*/)
}
}
Edit:
This can also maintain Java interoperability by using the toX() pattern, A.into(): B would be A.toB()
Well if you want to achieve the demonstrated method, it
requires a hacks to check what type it is, and then return to it with a cast, like the pattern get(Class<T>): T
Doesn’t allow for externally declared conversion methods, like String.into(): URL in the example
Edit:
You can do something with reflection and get “to$class.simplename”, but that means it is resolved at runtime instead of compile time, and additional checks have to be done, instead of it being statically resolved at compile time. Which is, again, a hack and doesn’t allow for extension.
Automated coversions are very often a bug farm. Kotlin design went for not doing any automated conversion.
Indeed it is, that’s why I didn’t say it should be fully automated, the idea behind the block is to only allow a certain type to be automatically converted, similar to the idea of with, though I can understand why it might not be the part of the final addition, which is why I said “or even”
This (well, without the automatic conversion part) is in fact a special case of a more general pattern – allowing functions with signatures which are identical except for the return type, disambiguating between them by expected and/or explicitly mentioned return type at call site – right?
Well, not exactly, it can be trivially compiled into JVM like “toA”, “toB” etc, it’s just such a commonly used pattern I think there should be some standard to it. I wouldn’t put it in the same basket exactly, since resolving the collision isn’t the main point here.
Hm, you say resolving the collision isn’t the main point, but unless I’m missing something this collision is the only reason why this (again, excluding the auto-conversion part) can’t be done in Kotlin currently, right?
Well, not exactly, unless return type collision is clarified via a type parameter(which I doubt it would), it wouldn’t be the same.
Im more inclined to think of it as fun < T > into(): T which is then dispatched at compile time.
What’s wong with myString.let(::URL)? It’s certainly a little longer than URL(myString) but it shares the nice left-to-right of the .into() proposal that the direct constructor call lacks.
The String → URL example is a constructor call and those shouldn’t be more hidden than necessary.
What I miss far more (and just dealt with a few days ago with an inline that I certainly wouldn’t mind seeing in the standard library) is casting in “dot order”:
(x as Y) is certainly an improvement over java’s parentheses-hell of ((Y)x) and as? beats the java equivalent by an even larger margin, but they still require jumping back for parentheses if x is a complicated expression.
x.asOrNull<Y>()?.someYMethod() would work nicely left-to-right no matter how complicated x actually is. (the as-sans-? variation any.asOrCrash<Y>() might seem a little overdramatic in naming, but I do like the explicit “OrNull” in autocomplete lists)
That’s exactly what this pattern was aiming to solve D: the toX pattern is commonly used, and standardising it on a language level could be nice. Especially since this way, the type can be implicit. But the toX would be how its presented when interoperating with Java
No… I want compiler to decide which method to call…
The user would define
fun Point.into(): IntPair = IntPair(x, y)
fun Point.into(): Pair<Int, Int> = x to y
fun foo(pair: IntPair) {}
val point: Point
foo(pair.into()) // automatically calls the one that returns IntPair
which is stated quite clearly in my original post imo.
If I understand correctly, does that mean you want the standardization of conversion methods and the benefit of not having to type potentially longer name like .into() instead of .toURL() or .toJSON()?
Because you also still need to manually write the conversion methods.
Edit: I just now understood your intention
IMO the benefit is trivial and isn’t worth standardizing.
I only see the point in standardizing conversions if they enable implicit conversions so you don’t even have to type .into() like you can do in C++
But again, the Kotlin team has decided to not allow implicit conversions
That is correct, the point is just to unify all conversion methods into one method, Any#into(). Rust has a trait for this purpose. See Into in std::convert - Rust
I think it would make sense to consider use cases and the core problems it solves.
For me, I don’t see an into operator or adding it as a member of the Top class Any to be strong enough to overcome the minus 100 points rule. Yes, it has some pros but it’s not so beneficial on its own to be convincing.
Instead, a trait system, type classes, and other more powerful language concepts that would enable this style of conversion might be a better consideration.
Fantastic point, I had a similar feeling when I was thinking about the system. I wouldn’t be that upset either if it doesn’t get added, I just thought it could be a useful feature and made a proposal.
Annotate single-arg constructors to generate an .into or a .toX extension function with the parameter type as receiver?
I’m decidedly in the camp of those who wouldn’t like it at all to see this generated automatically for all single-arg constructors, because there are plenty of cases where the semantics are completely different (e.g. a mutable class with some form of owner/patent reference, that’scertainly not “the same data, but in a different shape”). Perhaps default for data classes?
And in the question of .into vs .toX, I’d prefer .toX by a wide margin. Because reading is important (reading would be one of the prime benefits of this entire thing, y.toX() would read better than X(y), particularly for non-trivial expressions in the place of y)
I agree with @tom000 . If Kotlin would support overloading functions by their return type, then I think your into() would be possible and it would become just a convention. I’m not sure, what do you mean here: