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

Inheritance should be transitive; implicit type-casting is not transitive #426

Open
charlesstaats opened this issue Feb 3, 2024 · 0 comments

Comments

@charlesstaats
Copy link
Contributor

charlesstaats commented Feb 3, 2024

In the documentation, there is a section explaining how to "fake" inheritance using implicit typecasting. This is somewhat misleading since inheritance is transitive, but implicit typecasting is not.

For instance, in Java, an ArrayList is a kind of List which is itself a kind of Iterable. Consequently, you can pass an ArrayList object to any function that accepts an Iterable parameter. But if you tried to imitate this in Asymptote by creating types ArrayList, List, and Iterable, together with implicit typecasts ArrayList -> List and List -> Iterable, you would still not be able to pass an ArrayList to a function that expects an Iterable parameter:

struct Iterable { }

struct List { }
Iterable operator cast(List L) { return null; }

struct ArrayList { }
List operator cast(ArrayList L) { return null; }

void doNothing(Iterable i) { }

ArrayList L = new ArrayList;
doNothing((List)L);  // works
doNothing(L);  // does not work (but would if implicit casting were transitive)

I see two potential solutions to this issue:

  1. (Recommended) Remove or amend the section in the documentation about imitating inheritance. (This technique doesn't seem to have been used much, and without transitivity it's not useful for complex hierarchies.)
  2. Make implicit casting transitive. Basically, this would involve making the it so that if you have, e.g., implicit cast operators guide -> path and path -> path[], you'd automatically get an implicit path operator guide -> path[] (it would no longer need to be defined explicitly in plain_paths.asy). This sounds nice, but there's a catch: If you also had implicit casts guide -> guide[] and guide[] -> path[], you'd end up with an ambiguous "casting route" and go back to needing an explicitly defined guide -> path[]. Even worse, someone could have code that was working perfectly well but then broke because someone introduced a new cast guide -> guide[] and therefore made the existing code ambiguous. This last issue — the great potential for very sensible changes to break very sensible downstream code — is why I am skeptical of introducing transitivity, even if it could be done easily (which I'm guessing it could not).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant