Variadic type arguments for type carrier

43 views
Skip to first unread message

Wojciech Potiopa

unread,
Jan 6, 2017, 12:01:40 PM1/6/17
to ceylon-users
Hello, my goal is to bound statically typed arguments to 'fun' function type arguments from other function/object.

shared Dest fun<out Dest, Args>(Callable<Dest,Args> adapter, Anything* args) given Args satisfies Anything[] {...}

This arguments are defined as Args and provided i thought it would be ok if i could pass this type arguments via some kind of TypeCarrier ?
This carrier should be initialized with single step initialization, like this:

Carrier<String> carrier=Carrier(`String`)

the same carrier initialized
for 2 type arguments

Carrier<String,Integer> carrier=Carrier(`String`,`Integer`)
the same with 3 and 4... etc.

or in multi step like initialization:

Carier<String> carrier=Carrier(`String`);
Carrier<String,Integer> newCarrier=carrier.append(`Integer`);

how to define such generic Carrier ?

I thought maybe:
class Carrier<Args>(Type<Args>* args){}
But this wont work as:

carrier=Carrier(`String`,`Integer`)

will produce
Carrier<String|Integer>

Thanks
Wojciech




Wojciech Potiopa

unread,
Jan 11, 2017, 11:09:42 AM1/11/17
to ceylon-users
Hello i would really appreciate help here. After a week of investigation i see there is no possibility for such thing in Ceylon. The problem is in Ceylon multpile type params carried with one generic parameter like <Types> can only produce multiple valued parameters with sequence (it is a bit hard even to describe it), you can do this by adding constrain :
given Types satisfies Anything[]. This can be achieved if class is parametrized statically like
Carrier<[String,Integer,Character]>("a",3,'$');
But using Type<> to automatically constrain, always will produce String|Integer|Character rather than sequence/tuple [String,Integer,Character].
Carrier<[Class<String,Anything>,Class<Integer,Anything>...]>
defined like
shared class Carrier<Types>(Types types) given Types satisfies Type<Anything>[]  {}

but when i try to use it i can't strip off the Class<,Anything> to just provide tuple of types [String,Integer,Character]

or

i can defined like
shared class Carrier<Types>(Type<Types>* types)   {}

but in result i'll get
Carrier<String|Integer|Character>

which i cannot fed to Callable<,Types> neither as it should be [String,Iteger,Character]

:(

John Vasileff

unread,
Jan 11, 2017, 12:57:07 PM1/11/17
to ceylon...@googlegroups.com
I’m not sure I understand what you’re trying to do, but perhaps this will help.

Starting with your original example, you can do this:

    Dest fun<Dest, Args>(Dest(*Args) adapter, Args args)
            given Args satisfies Anything[]
        =>  adapter(*args);

    value four = fun(times<Integer>, [2, 2]);

Perhaps your goal is to be able to call “fun” without the Tuple, like:

    value four = fun(times<Integer>, 2, 2);

but I’m not sure that’s possible. I mean, you could do something really complicated like the code below, but it involves an extra step to create an “integerProcessor”, which probably isn’t what you want:

    Return(*Tuple<Argument|Return(*Arguments), Return(*Arguments), Arguments>)
            funfun<Return, Arguments, Argument>()
            given Arguments satisfies Argument[]
        =>  flatten((Tuple<Argument|Return(*Arguments), Return(*Arguments), Arguments> adapterAndArgs)
            =>  let ([adapter, *args] = adapterAndArgs)
                adapter(*args));

    value integerProcessor
        =   funfun<Integer,[Integer,Integer],Integer>();

    value nine = integerProcessor(times<Integer>, 3, 3);


John


-- 
You received this message because you are subscribed to the Google Groups "ceylon-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ceylon-users...@googlegroups.com.
To post to this group, send email to ceylon...@googlegroups.com.
Visit this group at https://groups.google.com/group/ceylon-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/ceylon-users/28ec9b13-6707-4343-b0cf-4a071052a300%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Wojciech Potiopa

unread,
Jan 11, 2017, 2:59:32 PM1/11/17
to ceylon-users
Ehh it is hard to explain maybe an example will help.
My goal is to process annotations over classes, their methods attributes etc. Then combine provided metadata into some object. This must be configurable and information how to process those annotations would be provided in assertJ style

by("me")
shared
interface Source{

by("me method1")
shared formal
void someMethod();


by("me method2")
shared formal
void someOtherMethod();


shared formal void nonAnnotatedMethod();

}


It should be parsed to object like this


shared class Info(classAuthors,methodInfos){

shared String[] classAuthors;

shared MethodInfo[] methodInfos;


}
shared class MethodInfo(author,isFormal){
shared String[] author;
shared Boolean isFormal
}



Now i want to describe to my processor how should he process annotations

from(`Source`).copy(`AuthorsAnnotation.authors`).to(`Info.classAuthors`); //must be staticaly type checked

So this i have already implemented, but processor should also handle adapting other types.

from(`Source`).methods.adapt(`AuthorsAnnotation`,`SharedAnnotation`,`FormalAnnotation`).to(`Info.methodsInfo`).via(adapter);//must be staticaly type checked


shared MethodInfo adapter(AuthorsAnnotation authors,SharedAnnotation isShared,FormalAnnotation isFormal){
//adapter code
}
 



To make it work i must  be sure that .via(adapter) method is defined as Callable<MethodInfo,[AuthorsAnnotation,SharedAnnotation,FormalAnnotation]) And this is what i want to pass, information gathered
with "adapt(`AuthorsAnnotation`,`SharedAnnotation`,
`FormalAnnotation`)" to last part of execution flow "
via(adapter)"

via would be defined as

shared Dest via<out Dest, in Args>(Callable<Dest,Args> adapter) given Args satisfies Anything[] {...}

I have to hold this Argument types somehow to feed "via"  method and make it caller would have to match the provided erlier args.
So for this example generic constrains should match "via " as

MethodInfo via<MethodInfo, [AuthorsAnnotation,SharedAnnotation,FormalAnnotation]>(Callable<MethodInfo,[AuthorsAnnotation,SharedAnnotation,FormalAnnotation]> adapter)

How to create kind of TypeCarrier (TypeTupple) to change and carry staticaly typed types:  `AuthorsAnnotaion`,`SharedAnnotation`,`FormalAnnotation` into [AuthorsAnnotation,SharedAnnotation,FormalAnnotation] but not [Class<AuthorsAnnotation,[...]>,Class<SharedAnnotation,[...]>...] and not [AuthorsAnnotation|SharedAnnotation|FormalAnnotation]

Thank you
Wojciech

John Vasileff

unread,
Jan 11, 2017, 4:31:55 PM1/11/17
to ceylon...@googlegroups.com
Ok, I think I’m starting to understand this issue. It seems you need:

1) a value of type [Class<Annotation>*] for use in code that uses the meta model to obtain an [Annotation*]
2) a type parameter that satisfies [Annotation*] to use for the parameter type in the “via()” method. This of course must align with the value in 1.
3) a way to call the Callable passed to “via()” using the annotation values discovered using the meta model.

I don’t know how this can be done, but to further explore the issue, consider the following, which does compile:

    class AdapterCaller<Arguments>() given Arguments satisfies [Annotation*] {
        // `Arguments` may be Class<> for Empty, Tuple, Singleton, ArraySequence,
        // or some other Sequence we don't necessarily know about.
        shared Result via<Result>(Result(*Arguments) adapter) => adapter(nothing);
    }

    void run() {
        value ac = AdapterCaller<[AuthorsAnnotation, SharedAnnotation]>();
        String result = ac.via {
            String adapter(AuthorsAnnotation a, SharedAnnotation b) => "result";
        };
    }

AdaptCaller() does not have a value parameter for the [Class<Annotation>*], because I don’t know how to form such a type from Arguments without something like https://github.com/ceylon/ceylon/issues/5838#issuecomment-165717491, and even then, I’m guessing type inference would not work, so you’d still have to explicitly provide type arguments.

Now, how do we obtain a [Class<Annotation>*] from `Arguments`? We could *try* with a bunch of meta programming that inspects type parameters, and recursively processes Class<Tuple, …>s. But we may encounter ArraySequences or other Sequential types, some of which may not be known in advance. This https://github.com/ceylon/ceylon/issues/5550 would help.

Finally, how do we call the passed in adapter function? We’ll have a list of annotations of type [Annotation*] obtained via meta programming, but adapter() will require arguments of type Arguments; we can’t simply do adapter(*discoverdAnnotations). So, I think https://github.com/ceylon/ceylon/issues/5806 would be necessary.

So this is a pretty pessimistic view. It seems to me you’ll need to give up some type safety or flexibility. But I’d be really interested if anyone else has better ideas.

John


Wojciech Potiopa

unread,
Jan 12, 2017, 11:09:51 AM1/12/17
to ceylon-users
John, thank You very much for answering. I wonder if providing [Annotations*] couldn't be expressed in kind of builder representation so from frontend part would be
from(`Source`).methods.addapt(`AuthorsAnnotation`).append(`SharedAnnotation`).append(`FormalAnnotation`).to(`Info.methodsInfo`).via(adapter);

Parameters could be carried using Type<[]> like
shared void appendTest() {
   
Type<[AuthorsAnnotation]> single = create(`AuthorsAnnotation`);
   
Type<[AuthorsAnnotation, SharedAnnotation]> double= append(single, `SharedAnnotation`);
   
Type<[AuthorsAnnotation|SharedAnnotation, FormalAnnotation]> failed = append(double,`FormalAnnotation`);//failed :(
}


shared
Type<[NewType]> create<NewType>(Type<NewType> type){
   
return `[NewType]`;
}

shared
Type<[Arguments,NewType]> append<Arguments,NewType>(Type<[Arguments*]> args,Type<NewType> newType) {
   
return `[Arguments,NewType]`;
}
but This implementation looses number of Arguments in tuple for more than two :/. I see i will have to think about what You have proposed, also don't know how to define "via(...)" method for this. Hope in future Ceylon will support this kind of operations

John Vasileff

unread,
Jan 12, 2017, 11:28:11 AM1/12/17
to ceylon...@googlegroups.com

On Jan 12, 2017, at 11:09 AM, Wojciech Potiopa <wojciech...@gmail.com> wrote:

… I wonder if providing [Annotations*] couldn't be expressed in kind of builder representation …

Yes, I had exactly the same thought! But I haven’t tried to work that out.

John
Reply all
Reply to author
Forward
0 new messages