-
Notifications
You must be signed in to change notification settings - Fork 5
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
Improve stability of enum proxies #200
Comments
Prior art:
|
Bumping always solves the problem, but since bumping is a pain in the ass people avoid it whenever possible. Most of the time they just fix everything when changing enum values. But it's easy to forget an empty commit to those modules that don't require source change, just server side recompile. This is often forgotten, and will be forgotten whatever we do. The first solution fixes problems like this, so I vote for that. We should also suggest bumping when the change occurs in cross team module boundaries. |
There are more benefits to shared enum instances, like using objects as enum values. That was the original implementation in Spaghetti 1.0, too. However, there's benefits in how enums (and constants) are handled now: simplicity. The only JS object your module gets from a Spaghetti dependency during runtime is the dependent module object, and only that needs to be exposed to your module's code—all the rest is in the generated code. Also, designing for making breaking changes without administering to those breaking changes seems like a bad idea. When it comes to making changes to enum values, there are two options:
|
I agree. Still, let's dissect this: There are three interesting cases removing, appending and reordering. (Adding is just appending + reordering. Renaming is just removing + adding.)
For what it's worth, introducing the indirection would make it braindead to reorder without causing breakage. I don't have to think about it as a programmer, and there is nothing I can mess up by miscalculating assigned values. That is a win. I am willing to give up some simplicity on the implementor side for this. @lptr What were the complexities that made you move away from shared values originally? Would we have the same level of complexity if we would still restrict values to integers? |
Problem
When generating headers for a module, we currently regenerate verbatim each enum defined in a module dependency, see e.g. here and here.
When operating within one language we would not need to do this, but could directly import the enum from each foreign module. However, as we cross language boundaries, we need to make the enums comprehensible for each language.
The current solution of just regenerating the whole enum in the module language is problematic over time in the light of independent compilation. For example we start with
and refer to values of this enum in another module by name,
Now the order of the cast changes slightly
while everything else stays the same.
Because A and B are compiled independently, as long as B is not recompiled after the changes to A, it will mistake the value it receives from
A.getStooge()
as not beingLarry
because its locally generated enum definition is out of sync (1 != 2
). Clearly, this is conceptually a breaking change in the API and A's major version should be bumped.Proposed Solution
There is however a way of reducing the impact of missed version bumps. While we clone enums from dependencies, we don't do this for functions exposed on dependencies: We merely create proxies that provide a typed interface. The same can be done for enums.
Instead of generating
Stooges
from above asin the TypeScript headers for B, we use an indirection to the canonical values in B
and thereby keep the value of each enum name stable across modules.
The enum proxy in B will still be out of sync after
Shemp
is added to A, but potential for breakage is reduced.Second Thoughts
This may lead to developers being less motivated to bump major versions, which is still necessary: What if
A.getStooge()
changes to returnStooges.Shemp
? B is unprepared and likely to break. Is it maybe still preferable to force major version bumps on changes to enums?The text was updated successfully, but these errors were encountered: