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

Type Safety for overloaded operators where T union{...} is used for more than 1 port #831

Open
emil14 opened this issue Jan 11, 2025 · 1 comment
Assignees
Labels

Comments

@emil14
Copy link
Collaborator

emil14 commented Jan 11, 2025

This issue is very close to #832 but describes a problem that was always existing in the language, while 832 describes the one that comes with tagged unions

Here we talk about + operator, but this applies to any overloaded operator with multiple ports using T (including 1 input and 1 output port of type T)

Problem

The + operator is designed to work with both numbers (int) and strings (string). Since the language is statically typed, the type system must prevent mixing different types to avoid invalid operations, such as adding a number and a string.

However, the current type system supports parametric types and algebraic unions, leading to the following problem:

  1. The + operator maps to a function add(a: T, b: T) -> T, where T is int | string (a union type).
  2. This allows passing arguments like a: int and b: string, which is logically incorrect but valid according to the type system.

Possible Solutions

  1. Extend the type system to enforce that arguments must either both be int or both be string.
  2. Add compiler-specific magic to check the homogeneity of argument types specifically for operators.
  3. Perform runtime type checks, though this would impact performance.
  4. Leave the current implementation as-is, assuming that developers will manually avoid mixing types.

Task

Find a way to implement the + operator that:

  • Ensures type checks are enforced at compile-time.
  • Disallows mixing types (e.g., int and string).
  • Avoids adding excessive complexity to the type system.

Any solution that strikes a balance between simplicity, performance, and strict type checking will be considered.

@emil14 emil14 self-assigned this Jan 11, 2025
@emil14
Copy link
Collaborator Author

emil14 commented Jan 11, 2025

I think for operators this problem could be solved by changing how overloading works

The thing is - type-system doesn't really know about overloading. It only affects what runtime implementation to choose, but not what compile-time signature to use for type-checking

#extern(int_add)
def Add(left int, right int) (res int)

#extern(float_add)
def Add(left float, right float) (res float)

#extern(string_add)
def Add(left string, right string) (res string)

We need to think how this affect type-checking for interface implementation (not implemented yet) though, especially for reducers


The problem of complexity that Go solves by simply not have (user-land) overloading could be solved kinda the same way - only allow overloading inside stdlib

Another way to work with this could be - style guide + linting

@emil14 emil14 moved this to In Progress in Nevalang Project Jan 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: In Progress
Development

No branches or pull requests

1 participant