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

Object members switch #7446

Open
Voiteh opened this issue Mar 3, 2019 · 9 comments
Open

Object members switch #7446

Voiteh opened this issue Mar 3, 2019 · 9 comments

Comments

@Voiteh
Copy link
Contributor

Voiteh commented Mar 3, 2019

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
Copy link
Contributor Author

Voiteh commented Mar 4, 2019

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
Copy link
Contributor

xkr47 commented Mar 4, 2019

Some ideas..

  • use a map somehow:
value memberMap = map {
  `PersonDb.personAge` -> `PersonDto.age`,
  `PersonDb.personName` -> `PersonDto.name`
};
  • use annotations on members in either PersonDb or PersonDto like:
class PersonDb(
  Integer id,
  mapToDto(`PersonDto.name`) shared String personName,
  mapToDto(`PersonDto.age`) shared Integer personAge
){}

@gavinking
Copy link
Contributor

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

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

@Voiteh
Copy link
Contributor Author

Voiteh commented Mar 5, 2019

@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
Copy link
Contributor

@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
Copy link
Contributor Author

Voiteh commented Mar 6, 2019

@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
Copy link
Contributor

@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
Copy link
Contributor Author

Voiteh commented Mar 6, 2019

@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
Copy link
Contributor

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

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

No branches or pull requests

3 participants