Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

invoking methods with no inference and all default type arguments #3897

Closed
CeylonMigrationBot opened this issue Sep 20, 2013 · 13 comments
Closed

Comments

@CeylonMigrationBot
Copy link

[@FroMage] Support:

function f<T=Object>(T t) => t;
Object obj = f<>("hello");

This was disabled by #3896 and is actually the only way to call generic methods where type inference fails without warning the user (I think there's another issue about that already) and where all type arguments have good valid defaults, rather than the wrong ones that would be inferred.

We have syntax to support using default type arguments after the first one, just not the first, which is really weird.

I suppose that if type inference would use defaulted type arguments when it can't possibly infer anything useful, that would help too.

[Migrated from ceylon/ceylon-spec#791]
[Closed at 2015-05-13 20:17:08]

@CeylonMigrationBot
Copy link
Author

[@gavinking] Not for 1.1

@CeylonMigrationBot
Copy link
Author

[@gavinking] So a couple of things have come up recently which have convinced me to do something here:

  1. People keep being surprised about the fact that type inference takes precedence over default type arguments, and so it's clear that there is a design error here.
  2. The choice to make the type expression Map mean "use default type arguments" is unnaturally constraining the syntax for higher order generics in higher order generics #3860.
  3. I kinda like the idea of implicit default type arguments in implicit defaults for variant type parameters #4397, but I don't like that you would get them used by accident.
  4. I keep running into bugs like stack overflow for broken supertypes #4399 where the typechecker starts inappropriately trying to compute default type arguments and blowing up.

Therefore, I propose to:

  • Introduce the diamond syntax Type<> or f<>("hello") to explicitly ask for defaults in both type and value expressions, as proposed by @FroMage.
  • Make a type expression like Map with a missing argument list mean a type constructor instead of using defaults. This is in principle a breaking change to the syntax of Ceylon, but I note that we essentially never use the previous interpretation, because it's simply too confusing. There are a couple of places where we write Category, but we can easily change that to Category<>. Perhaps I could simply deprecate the old interpretation rather than making it an actual error. But that wouldn't solve problem 4.
  • Implement implicit defaults for variant type parameters #4397.

Everyone, WDYT? Any objections?

@CeylonMigrationBot
Copy link
Author

[@lucaswerkmeister] Let me make sure I understood this correctly:

f<Map>();

This currently means “call f with the type argument Map<Inferred,Inferred>”, and after the change would mean what’s currently f<@Map>().

Map m = Map { 0->"0" };

This would not change: Both Maps are not type expressions (one is a a declaration type, one is an expression). In both cases, the type arguments are inferred.

Right?

@CeylonMigrationBot
Copy link
Author

[@gavinking]
@lucaswerkmeister No. Currently f<Map>() is an error because Map has type parameters which are not defaulted.

What changes is the interpretation of:

f<Category>()

This currently means f<Category<Object>(), since Category has a default type arg. It would now mean f<@Category>().

@CeylonMigrationBot
Copy link
Author

[@gavinking] @lucaswerkmeister, and no, your second example is completely wrong. Only the LHS is a type expression, and so for that the interpretation changes. But both before and after it is an error, since Map has no default type parameters, and since type constructors can only occur in type argument lists.

@CeylonMigrationBot
Copy link
Author

[@gavinking] @tombentley points out that this might affect a lot of metamodel code where I guess people tend to write Class sometimes, and now they would need to write Class<>. So I should only deprecate the syntax, not remove it.

@CeylonMigrationBot
Copy link
Author

[@FroMage] I would have kept Category in type expressions as using default values (since there is no inference in type expressions), but what you proposed would make it more regular, at the cost of being more verbose.

@CeylonMigrationBot
Copy link
Author

[@gavinking] @FroMage Well 2 and 3, and the analogy to what we do with defaulted arguments of functions push me toward thinking it was a mistake. I mean, we don't say that writeLine means writeLine().

@CeylonMigrationBot
Copy link
Author

[@quintesse] But in that last example they aren't 100% equivalent, is it? I mean we also don't write writeNewline to call a method that has no parameters, but I guess you'd still want ot use Foo to refer to a class that has no type parameters.
But if you're sure that difference doesn't cause any problems I don't mind this change.

@CeylonMigrationBot
Copy link
Author

[@gavinking] @quintesse Wrong analogy. Integer is analogous to a value like int, List<T> is analogous to a function like writeLine(String s).

@CeylonMigrationBot
Copy link
Author

[@gavinking] I have implemented this. For now, you just get a usage warning for the old syntax, not an error.

@CeylonMigrationBot
Copy link
Author

[@gavinking] This is done, but I still need to update the spec,

@CeylonMigrationBot
Copy link
Author

[@gavinking] Done.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants