question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

implicit conversions for Java types

See original GitHub issue

I have long opposed defining any implicit type conversions in the language, because of the ambiguities and confusing behavior that can result. For example, consider what happens if we define an implicit type conversion from Java List to Ceylon MutableList, and write:

javaObject.someList.size

The programmer might expect size to refer to the attribute MutableList.size of type Integer, but in fact it actually refers to the method size() of List. Even worse ambiguities arise if implicit conversions are transitive.

As we’ve seen, however, confusion and inconvenience can also arise from not having any sort of implicit type conversions, for example, when Java’s String type leaks into Ceylon code, or when strings aren’t assignable to Java parameters that accept CharSequence.

Yesterday, I realized that there is an approach to implicit conversions that doesn’t lead to the ambiguities I’ve always been bothered by. Traditional implicit type conversions are only applied when the original type is not assignable to the declared type of something. They are thus, in some sense, “lazy”, and the original type always has the chance to “leak out”.

But for the specific case of inter-language interop, that’s actually not what we need. What if we defined some type conversions that were always applied, as soon as possible? That is, as soon as we have an expression of type java.lang.String, the conversion to ceylon.language::String is immediately applied, and no operations of java.lang.String are ever visible. Then, essentially, no Ceylon code would ever be able to interact with the type java.lang.String except to the extent that it can occur as a type argument in a generic type.

Likewise, no Ceylon code would ever interact directly with a java.util.function.Predicate<T>, since any expression of that type would immediately be converted to Boolean(T).

It seems to me that this solution is perfect for protecting Ceylon code from Java types, including String, primitive wrapper classes, @FunctionalInterfaces, Iterable, List, Set, Map, and perhaps even primitive arrays (which could be converted to Array). I think and hope it would also work for the special transformation CharSequence <-> List<Character>, which I admit is a slightly tricky case.

So the next problem that arises is how to pass a value to a Java parameter declared with one of these “hidden” types. Since we can no longer form an expression of type java.lang.Integer, we can’t call any Java method that accepts a java.lang.Integer.

Well, the solution is quite similar: the typechecker, when it comes to assign a type to parameter of one of the “hidden” types, actually applies the same conversions, and arrives at a type to which we can assign!

Obviously, this implies a mathematical property of the transformation, namely that it is a bijection. Fortunately, I think we can shoehorn our transformations into a bijective function. However, I still need to verify that.

For this to really work correctly and transparently, there’s one big caveat: the set of transformations and reverse transformations would need to be applied every time we assign a supertype like Object or Number to or from Java! Actually CharSequence also counts as one of these “supertypes”, so it’s not that special. As is Iterable I guess.

Anyway, I think this is a very strong way forward, and just requires thinking through the details. I believe it can be made to work.

WDYT?

Issue Analytics

  • State:open
  • Created 7 years ago
  • Reactions:1
  • Comments:33 (33 by maintainers)

github_iconTop GitHub Comments

2reactions
FroMagecommented, Apr 12, 2016

Stef was right all along

stef-was-right-shirt stef-was-right-mug

0reactions
FroMagecommented, Sep 20, 2016

Now that 1.3.0 is out, we can resume discussing those solutions. In a conversation with @gavinking he mentioned that the biggest drawback to auto-coercion is that it requires IDE support, because quick-fixes have to learn that coercion exists. To side-step the compatibility issue he proposes that this mapping is only turned on by a compiler flag.

If we do flags for type mapping, I don’t think we can do this per-module, as that would introduce incompatible types in hierarchies in different modules that have a different type mapping policy. But globally this should work. Note that a type mapping change that is optional means either that we can’t change how types are compiled, just how they appear in the model (which means a lot of work in the backend to untangle that), or that those things are reflected in how they are compiled and we run into erasure issues of having to figure out the proper erasure of a type depending on the type mapping policy that was in use in super-types (again a lot of work in the backend). Breaking compat would make this much easier for the backend, and frankly may be the only sane solution if we go this way.

If we’re going to do flags, I can also propose that the auto-coercion solution is turned on by flags, and can even be per-module or per-file (since it’s entirely turned on/off by the typechecker).

We could even support both options and let users pick.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Implicitly Typecasting in Java - Javatpoint
In implicit typecasting, the conversion involves a smaller data type to the larger type size. For example, the byte datatype implicitly typecast into...
Read more >
Type conversion in Java with Examples - GeeksforGeeks
Explicit Type Casting in Expressions ... While evaluating expressions, the result is automatically updated to a larger data type of the operand.
Read more >
Type Conversion in Java - Explore Automatic & Explicit Type ...
Implicit Type Conversion ... Java converts shorter data types to larger data types when they are assigned to the larger variable. For example,...
Read more >
Custom Implicit Conversion in Java - Stack Overflow
Only built-in types have implicit conversions. · Explicit conversion (in java) is called a cast. for example, int q = 15; double x...
Read more >
Chapter 5. Conversions and Promotions
... the Java programming language performs an implicit conversion from the type of the expression to a type acceptable for its surrounding context....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found