Skip to content
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

Name clashes during inheritance #97

Closed
markusvoelter opened this issue Mar 24, 2023 · 6 comments
Closed

Name clashes during inheritance #97

markusvoelter opened this issue Mar 24, 2023 · 6 comments

Comments

@markusvoelter
Copy link
Contributor

markusvoelter commented Mar 24, 2023

Name-clash problem as described in section 3.3

Example: concept X inherits from concepts A and B who both define a feature named f

classDiagram

class A {
  string f
}

class B {
  string f
}

A <|-- X
B <|-- X

Decisions:

  • we treat A.f and B.f as distinct f's in X (semantically they are different)
  • remaining issue: who can continue to use the name f, because the name (not the feature) is ambiguous (relevant for situations where we access f by name and not by key; ie., generated code)
  • solve the problem for the place where we use by-name reference, aka the code
  • generator that produces said code must rename one of them (i.e. 3.3.3. Require qualification)
    • potentially user-guided somehow (e.g. by annotations on X; close to 3.3.2. Rename conflicting names)
    • or automated
    • implementation detail of the API generator
  • the alternative of merging is stupid because we imply semantics in a name (i.e. 3.3.1. Merge compatible names)
  • disallowing conflicts is unrealistic in the face of reuse of metamodels (i.e. 3.3.4. Disallow conflicts)
  • our solution might lead to ugly names, but since the situation is rare in the first place we consider this acceptable
@enikao
Copy link
Contributor

enikao commented Mar 24, 2023

Note: This can lead to different semantics than e.g. Java.

Consider the following Java interfaces:

interface A {
  String getF();
}

interface B {
  String getF();
}

class X implements A, B {
  public String getF() {
    return "hello";
  }
}

Java merges A.getF() and B.getF() inside X.

This doesn't work any more if they return different types:

interface A {
  String getF();
}

interface B {
  Integer getF();
}

class X implements A, B {
  // compiler error: 'getF()' in 'X' clashes with 'getF()' in 'B'
  public String getF() {
    return "hello";
  }
}

(This is the disallow case.)

That's why we treat this differently in LIonWeb:

interface A
  derived property f: String

interface B
  derived property f: Integer

concept X implements A, B

X has two different properties f now, which might be renamed by the API generator:

X myX = new X
myX.A_f = "hello"
myX.B_f = 123

@joswarmer
Copy link
Contributor

Maybe a bit late, but the decision to treat the two f's in the first example as two properties is very different to the way this is done in most (at least Java and TS/JS) languages and e.g MPS (and probably EMF) and therefore users/developers will be confused by this.

In e.g. TS (which I mainly use these days) it is quite common to implement multiple interfaces with the properties with the same name. I

I don't understand/remember why we decided to use this non-standard way of dealing with this.

@enikao
Copy link
Contributor

enikao commented Jun 9, 2023

Maybe a bit late, but the decision to treat the two f's in the first example as two properties is very different to the way this is done in most (at least Java and TS/JS) languages and e.g MPS (and probably EMF) and therefore users/developers will be confused by this.

This is documented in the comment above.

I don't understand/remember why we decided to use this non-standard way of dealing with this.

All the variants are discussed at https://github.com/LIonWeb-org/organization/blob/main/lioncore/conceptinterface.adoc#33-name-clashes

In short: Existing languages have the same issue, as soon as the two f's differ in anything else but the name (e.g. f: int and f: string). Then it gets intricate what is supported by which language -- and we don't want to go for the smallest common denominator.
Also, systems that do support this (e.g. MPS) would need to deal with it when exporting to LIonWeb.

With this decision, we let the mapping to each language decide what's most suitable for that language.

@joswarmer
Copy link
Contributor

I see the discussion, but I do not see a decision in https://github.com/LIonWeb-org/organization/blob/main/lioncore/conceptinterface.adoc#33-name-clashes.

If we take the decision above it becomes very hard to generate code for the meta-model. You can solve this in several ways:

  • Generate some kind of "qualified" name for each property, leading to unreadable and unintuitive code because every property will have a very long (qualified) name.
  • Analyse the meta-model and only generate something "qualified" for this properties that are repeatedly inherited. Problem here is that the generated code for one class/interface X will change if something is changed in the meta-model, even though the class/interface X itself is not changed. This is a very volatile solution. Also, if there is generated code for a language you cannot change, this is even impossible at all.

Therefore from the perspective that we want to be able to generate a typed language API (Java, TS, ...) we should consider solution https://github.com/LIonWeb-org/organization/blob/main/lioncore/conceptinterface.adoc#331-merge-compatible-names or https://github.com/LIonWeb-org/organization/blob/main/lioncore/conceptinterface.adoc#334-disallow-conflicts

Maybe there are better solutions than the two I described, but I don't see them yet.

@enikao
Copy link
Contributor

enikao commented Aug 31, 2023

@joswarmer Can we close this?

@joswarmer
Copy link
Contributor

Should close this

@enikao enikao closed this as completed Jan 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants