-
-
Notifications
You must be signed in to change notification settings - Fork 888
Fix record constructor functions code generation #5110
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
base: main
Are you sure you want to change the base?
Fix record constructor functions code generation #5110
Conversation
3218098 to
2c061d4
Compare
|
I think this is not the right way to solve this, we should change the code generation for js so that they are indeed the same. I think this is already the case on the erlang target |
|
@giacomocavalieri I think the behavior is consistent across all targets (js and erlang). That's why I thought this was expected and agreed upon (functions are treated as objects and are compared by their unique memory references): type Comparison {
Wibble
Wobble(String)
}
pub fn main() {
echo Wibble == Wibble
echo Wobble == Wobble
echo fn() {} == fn() {}
echo fn() { 3 } == fn() { 3 }
} |
|
Oh wait... we definitely should change the way we handle function comparisons: type A {
A(String)
}
fn a() {}
pub fn main() {
echo a == a // True
echo A == A // False
}I’m unsure what the right criteria for function equality should be. For example, should two identically defined anonymous functions count as equal, or only named functions/constructors? My assumption is one would expect memory references to be checked, and as two anonymous functions are distinct objects only functions with the same name would compare as equal. |
aee0fd9 to
4247ce5
Compare
|
I considered manually changing how constructor functions are compared at runtime instead of making a breaking change to codegen. However, tracking dynamic code flow at runtime would add unnecessary overhead during compilation. In my opinion, modifying codegen is the better approach: type Bar {
Foo(String)
}
fn a() {}
pub fn main() {
let b = a
let c = a
// because of modified codegen, d and f are now references
// to the same named function associated with Foo
let d = Foo
let f = Foo
echo b == c // True
echo d == f // False -> True
} |
b1ecc46 to
6d9bc19
Compare
For performance reasons we want to introduce singleton values for record constructors and for zero arity variants, which would solve this too. This bit I'm unsure about is function capturing and anonymous functions. Do we have this issue with them today? |
92ecfe7 to
567141c
Compare
|
@giacomocavalieri @lpil I've updated code generation so record constructors are emitted as singletons, giving them the same equality semantics as named functions. I want to know your opinion on the changes and naming strategy I used: ErlangConstructor functions with arguments use When a constructor is referenced as a value, the compiler generates JavaScriptConstructor functions use When referenced as a value, the compiler simply uses the identifier The potential problem I see is Gleam users seeing compiler errors due to cached old codegen output when updating to next release. Not sure what to do with this. |
|
Thank you for the detail! We don't want to make any changes to the API of generated Erlang modules, so we cannot add constructor functions. I think we should disable this warning for record constructor functions, the same way we do for anonymous functions. |
@lpil I think I overstated the risk of people hitting compiler errors due to cached codegen when upgrading. The change in API of erlang and javascript modules is not breaking in the sense that it doesn't modify any existing definitions, it's just adding new functions for constructors? For instance, resolving issues like #5127 (where some unused types should not be emitted) would require such changes. The PR with minor changes (like if there is any definition for constructor function cause recompiling) will not break any existing code, so I guess it's fine? |
567141c to
ebb9951
Compare
True#5108