New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reified/Runtime Type Aliases #1359
Comments
Yeah, I've had ideas along these lines before. But never sat down and really tried to think it through. It's an interesting idea. |
I like this idea, but I'm a little wary of the |
What if there were a more generalized concept of this? Suppose there was a syntax that was defined as "The reverse of backticks" (perhaps ' '). IE: Then one could write:
Without making alias keyword special in any way. Or more concisely:
|
@tkaitchuck What you're now proposing is basically dependent typing (without Pi or Sigma). You'd be able to use a runtime type in any place where a compile-time type is accepted. A system like that can totally work, but it needs very careful design, and I believe @gavinking has stated a negative reaction to features like this before. |
It's only considered dependent typing if you also do computation with the values at the type level. This looks to me like unpacking an implicitly existentially qualified type variable. That's much easier to do right than dependent types. Generally syntax is the biggest challenge with this kind of stuff. |
@RossTate Oh, OK! I guess you'd know more about it than me. It still seems like you'd be able to pull stuff like this, though: class Sigma<A>(fst, tyMap, snd) {
shared A fst;
shared Type<out Anything> tyMap(A x);
shared 'tyMap(fst)' snd;
} |
Yeah, the difference is subtle. I suppose in your example the difference would be best illustrated by the fact that you couldn't guarantee that multiple occurrences of |
_!!!_ That just makes it worse; how is it remotely possible, given what you said, to guarantee that compilation terminates? Or is there something else preventing me from writing my |
I think our interpretations of the proposal differ. I interpreted That makes me think that things like |
Oh, I see. I guess one could still use stuff like |
@RossTate Sorry, but can something like this work?: class Type<out T>
{
// ...
}
String callSomething(Type<Object> theType, Anything arg)
{
assert(is theType.T arg);
return(doSomething(arg));
} Or, more interestingly: theType.T elseThrow(Type<Anything> theType, Anything obj)
{
if(is theType.T obj)
{
return(obj);
}
else
{
throw(Exception("``obj`` isn't of type ``theType``"));
}
}
void foo(Type<Object> someType, Anything someObject)
{
Object obj = elseThrow(someType, someObject);
// Here, we know that `elseThrow` will return at least an
// `Object`, because `someType` is of type `Type<Object`>,
// but if the `someType` is of a different type (let's say,
// `Type<Qux>`), at runtime, `elseThrow` will always return
// a `Qux`!
} That's something I feel like is interesting, but I'm unsure whether this can cause some sort of problem. |
We need something like that, to be able to pass runtime types as type arguments. This is specially useful for functions that require reified generics: void invokeController(Object container, Class<Controller,Nothing> klass){
alias ContainerType = type(container);
assert(exists method = klass.getDeclaredMethod<ContainerType,Response,[]>("handle"));
method(container)();
} Certainly the runtime behaviour of passing a reified generic from a Note that this is not enough to make it easy to scan for methods of certain parameter types given parameter instances: void invokeController(Object container, Object[] arguments, Class<Controller,Nothing> klass){
alias ContainerType = type(container);
// this would probably fail because it's not trivial to convert an Object[] to a tuple of each element type
// for example, we want a [Integer,String] and not an Object[] or [Object,Object]
alias ParameterTypes = type(arguments);
assert(is ParameterTypes arguments);
assert(exists method = klass.getDeclaredMethod<ContainerType,Response,ParameterTypes>("handle"));
method(container)(*arguments);
} But I suppose this can be fixed by a toplevel that turns a sequence of |
Yeah, nice examples. I think we'd still need an alias ContainerType = type(container);
assert (is ContainerType container); unless we stipulate cases where the narrowing would be implied (basically when using the result of |
So @FroMage's seems like it would work using the existential technique I mentioned. @Zambonifofex's examples, if I understand them correctly (I take it |
With reified generics, you can obtain an instance of
Type<T>
from a generic argumentT
. This proposal is to support the reverse: define a reified type aliasT
with an instance ofType<T>
.Reified (runtime?) type aliases would resemble type arguments. In fact, the behavior and capabilities of
T
andU
in the example below would be indistinguishable:An immediate benefit would be a greatly reduced need to use
apply
andinvoke
functions for meta programming, and a faster, safer bridge from meta to normal type checked code. I imagine a further benefit would be a tendency to create safer and more convenient apis due to the increased ability to use type arguments instead ofType<>
arguments.Note: another advantage above is that
doSomething
could have been a local declaration, which is not possible when a meta model reference is required.A couple usage examples:
Example 1: Type Conversion Service
ConversionService
provides functions to convert/coerce values from one type to another.toArray
converts anyIterable
to anArray
of the required type, converting elements as necessary.This much more closely resembles a normal Ceylon program, rather than an alternate approach using
invoke
. And, importantly, the assertions are 1) explicit, and 2) easy to reason about. There are no calls to functions that may throw because we provided the wrong argument to a parameter of typeType<Anything>
orAnything
.(See also #560)
Example 2: Configuration Service
This example is adapted from
ceylon/formatter/options/formattingFile_meta.ceylon
and contrasts style and error handling between the two approaches.The text was updated successfully, but these errors were encountered: