eclipse-archived / ceylon

The Ceylon compiler, language module, and command line tools
http://ceylon-lang.org
Apache License 2.0
395 stars 62 forks source link

Object members switch #7446

Open Voiteh opened 5 years ago

Voiteh commented 5 years ago

When using metamodel, for object information extraction, like member attributes or member functions. It would be nice to have possibility to switch over this extracted values.

For example I would like to create mapping between two representation of the same domain model, a DTO and database model, for some reason names of attributes does not match.

class PersonDb(Integer id,shared String personName,shared Integer personAge){}
class PersonDto(shared String name,shared Integer age ){}

Currently the simplest form of mapping between those two attributes I can make, look like:

Attribute<PersonDto>? mapAttributes(Attribute<PersonDb> dbAttribute) =>
    if(dbAttribute==`PersonDb.personAge`) then `PersonDto.age` 
    else if(dbAttribute==`PersonDb.personName`) then `PersonDto.name`
    else null;

And it would be nice to have something like this:

Attribute<PersonDto>? mapSwitchAttributes(Attribute<PersonDb> dbAttribute) =>
    switch(dbAttribute)
    case(is `PersonDb.personAge`){
        return `PersonDto.age`;
    }
    case(is `PersonDb.personName`){
        return `PersonDto.name`;
    }else{
        return null;
    }

Of course with exhausting requirement "Case types must cover all cases of the switch type or an else clause must appear"

Voiteh commented 5 years ago

Maybe rather than using switch keywordk for this, there would be another type of switch called member switch. It could be done on ClassOrInterface<Model> or on Member<> implementation. The first one would make switch on all members of ClassOrInterface, second one only on specific Member<> type like Attribute>?

xkr47 commented 5 years ago

Some ideas..

gavinking commented 5 years ago

@Voiteh would it work for you if these were declaration references, i.e.

switch (dec)
case (value PersonDto.name) { .... }
case (value PersonDto.age) { .... }
Voiteh commented 5 years ago

@gavinking I think so, as I just need to somehow connect references. Would it be possible to have exhausting switch though ("Case types must cover all cases of the switch type or an else clause must appear")? As if You get declaration out of Class<PersonDto>, You will have ClassDeclaration and loose the context of Type, for which this declaration is for. The same is for value PersonDto.age (ValueDeclaration), it doesn't provide compile time information about to which ClassOrInterfaceDeclaration it is connected to.

gavinking commented 5 years ago

@Voiteh well generally we don't consider a switch to be exhaustive unless you've explicitly declared that the list of members is exhaustive using an of clause. So I don't think this should be considered an exhaustive switch. (Adding a new member to a type is generally not considered a change that breaks client code!)

Voiteh commented 5 years ago

@gavinking I'm bit confused, how could You declare member using of keyword ? Is this, what You presented possible it in Ceylon 1.3.3 ? Can You give me full example using PersonDb/PersonDto definition and mapping method?

gavinking commented 5 years ago

@Voiteh well, here's an example of a class with an enumerated list of elements:

class Suit of hearts | diamonds | clubs | spades {
    String name;
    shared new hearts { name = "hearts"; }
    shared new diamonds { name = "diamonds"; }
    shared new clubs { name = "clubs"; }
    shared new spades { name = "spades"; }
}

Note that all the elements (constructors) are listed in the of clause. That's what makes a switch over them exhaustive.

Voiteh commented 5 years ago

@gavinking Ah I see what You ment now.

As for what I wrote "Is this, what You presented possible it in Ceylon 1.3.3" I ment :

switch (dec)
case (value PersonDto.name) { .... }
case (value PersonDto.age) { .... }

I couldn't make it compile in web IDE so i guess no...

gavinking commented 5 years ago

No, it's not possible today, but in principle it would be pretty simple to add.