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-assertion #749

Open
emil14 opened this issue Nov 4, 2024 · 3 comments
Open

Type-assertion #749

emil14 opened this issue Nov 4, 2024 · 3 comments
Assignees

Comments

@emil14
Copy link
Collaborator

emil14 commented Nov 4, 2024

Related to #747 #726 #725

Problem (Structural Typing)

The thing about type-assertions in Nevalang is that messages doesn't hold their compile-time type information at runtime. In Go this problem is solved with nominative typing - values know names of their types. In Neva this isn't the case - message of type User is just some struct. Also, runtime data-types are different than compile-time, they are much simpler and doesn't have anything like type-parameters.

I.e. there's no problem with asserting if any is bool, int, float or string but with anything more complex there will be problems. It's not possible to assert that v is list<int>, it's just a list. Same for structures. For enums it will probably be just int (maybe string if string-enums are a thing). For unions it's not possible at all, runtime doesn't know about their existence.

@emil14
Copy link
Collaborator Author

emil14 commented Nov 5, 2024

FYI TypeScript

TS just like Nevalang doesn't have compile-time (complex) type information at runtime, so the only way to e.g. assume if something is of specific shape is by raw trying to access fields

interface Cat {
    name: string;
    lives: number;
}

interface Dog {
    name: string;
    barks: boolean;
}

// Example data from a third-party library
const animals: (Cat | Dog)[] = [
    { name: 'Whiskers', lives: 9 },  // Cat
    { name: 'Fido', barks: true },    // Dog
];

// Type guard for Cat
function isCat(animal: any): animal is Cat {
    return (animal as Cat).lives !== undefined;
}

// Type guard for Dog
function isDog(animal: any): animal is Dog {
    return (animal as Dog).barks !== undefined;
}

// Function to handle animals
function handle(animal: Cat | Dog) {
    if (isCat(animal)) {
        console.log(`This is a cat named ${animal.name} with ${animal.lives} lives.`);
    } else if (isDog(animal)) {
        console.log(`This is a dog named ${animal.name} that barks: ${animal.barks}.`);
    } else {
        console.error("Unknown animal type");
    }
}

// Example usage
for (const animal of animals) {
    handle(animal);
}

We either have to follow same approach or add typesystem information to runtime


Even then we won't have original (unresolved) forms of types of things

@emil14 emil14 mentioned this issue Nov 6, 2024
@emil14
Copy link
Collaborator Author

emil14 commented Nov 9, 2024

This is related to #751 and #756

@emil14 emil14 added Critical and removed Major labels Jan 11, 2025
@emil14 emil14 self-assigned this Jan 11, 2025
@emil14
Copy link
Collaborator Author

emil14 commented Jan 11, 2025

Some dump from editor


Solving problem of asserting a specific type on message of type any

def OneOf(data any) (x int, y models.User, z any) {
    data -> type -> switch {
        (type int) -> x
        (type models.User) -> y
        _ -> z
    }
}

Parser/Sourcecode/Analyzer

  • New type sender. It's a special kind of sender that receives the message and sends its type-id. It's expected to be used like a single-port per side node and analyzer must check that.
  • Another one type_v2 sender. It's a completely different syntax and implementation. It's in (type ...) like binary/ternary operation expression (but it's not) and its right part is an entity reference, that must refer to a type-definition
  • Extend core.Meta with optional field extra any and put type-id there at parsing step. Create global counter and increment it for each type definition in the program.

Desugaring/Irgen

Runtime

  1. make each runtime.NewXXXMsg(...) constructor take a type-id as an argument. Example: runtime.NewIntMsg(42, 238475).
  2. add typeID uint64 field to runitme.internalMsg

???

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

No branches or pull requests

1 participant