> One of the key ideas with Ezno is that it attempts "maximum" knowledge of a source
I've been working on a new TypeScript-like language myself from scratch, which among other things takes this approach. Mine can do some of the numeric stuff shown here, but I'm jealous of (inspired by? :)) some of the crazier stuff going on here, like usage-based argument types and tracing not just value shapes but value reference identities
The "automatic generics" feature in particular is absolutely bonkers. It never even occurred to me that you could do that. I'm wondering if there are unforeseen edge-cases, but also wishing I had it at work. Clunky generics syntax is one of the worst parts of TypeScript, even while generic function types are one of its best parts.
Wow, and side-effects-tracking too! Amazing
I am curious whether some of these checks will be limited by JavaScript's dynamism. Part of why I'm doing mine as a new language is that JavaScript's semantics are just way too flexible to form some of the guarantees I feel like you need for some of this aggressive inference. But now I'm questioning that.
Either way, this is insanely impressive. Definitely not just yet-another-JavaScript-toolchian.
Thank you. Just checked out the Bagel post (https://www.brandons.me/blog/the-bagel-language) and it looks really cool. Identifying pure functions (whether that is by syntax annotation or from synthesis) is a really good idea, gives me some ideas for doing function inlining in Ezno. I like the "Misc niceties" section, a few of those may of may not be on Ezno's todo list :)
The automatic / inferred generic restrictions is quite cool. https://hegel.js.org/ got there before me! Basic restriction modification is quite simple e.g. `(x) => Math.sin(x)`, x wants to be a number so can add that restriction. It gets more difficult with higher poly types. `(someObj) => Math.sin(someObj.prop1.prop2)` requires modifying not just `someObj` but a property on a property on it. And `(x, y) => printString(x + y)` requires doing even more complex things. But its definitely possible!
Replying to both of you, I'm also working on something similar, but in Lua!
I've been searching for people who are doing this for inspiration and maybe exchanging ideas in chat. What I have seems very similar to Ezno when it comes to tracking mutations and side effects and the key idea of "maximum knowledge of a source"
I struggle a bit with communication about this topic as my way of learning has been more of a self taught trial and error process. It almost feels like the people who are building typesystems is speaking another language (especially those with a Haskell background), but I'm slowly starting to understand some of it. Your blog post however was easy to understand.
Inferring from usage is something I've been thinking about every now and then, and it seems doable if the type can mutate from some unknown type to the first expected type. In practice this doesn't seem to become a big deal if you always require input types to be typed (from arguments or some other external) but it's an interesting problem.
I think the way I would approach mutating someObj.prop1.prop2 is to do a mutation of the field when calling the function signature. I'd have to know a few things about prop2 though.
So it would effectively be something like Math.sin = (val) => {let [parent, key] = parentObject(val); parent[key] = number }
Then it would make use of the way i track mutations already.
My project's status is that it's not production ready but it's in the open. There's some use to the playground to analyze what Lua scripts might possibly do.
Not sure if I have any big plans, I just think it's fun and interesting to work on and maybe I want to use it for my other Lua projects. I'm not very happy with the codebase as I've written it in Lua. I'm trying to bootstrap it but it's growing in complexity faster than I can bootstrap it. But one step at a time and I should be there someday, maybe I can even port it to some other language like Rust when I have a better understanding of what I'm actually doing. :)
Fwiw, I took the approach of having a hard separation between stateful and functional code partly so that I could dodge most of these hard questions around mutation tracking ;)
The stateless code can be really aggressively inferred, and even re-ordered, inlined, detected as dead and thrown away, memoized, whatever else is useful. And then the (hopefully small) stateful code can just be typed at roughly the same level TypeScript already does
Automatic generics is how c++ templates behave. It is universally agreed upon to be absolutely horrible, now being remedied with what they call Concepts to constrain the generic signatures at least a little.
The issue is that when you have errors, it is impossible to determine if the error is at the caller, the callee or at the type signature. Essentially you have an equation of 3 dimensions with 3 unknowns. Same issue propagates into code navigation and refactoring.
It’s like regressing into a dynamically typed language except the errors are given during compile time. For small simple functions like the addOne example, it’s great to reduce boilerplate typing, but once you start relying on it for more complex types it can easily go out of hand.
I don't think the problem you describe would happen in the version seen in Ezno, since the arguments and return can still get explicit type declarations and the "generic" version is just a more-specific refinement of that
I've been working on a new TypeScript-like language myself from scratch, which among other things takes this approach. Mine can do some of the numeric stuff shown here, but I'm jealous of (inspired by? :)) some of the crazier stuff going on here, like usage-based argument types and tracing not just value shapes but value reference identities
The "automatic generics" feature in particular is absolutely bonkers. It never even occurred to me that you could do that. I'm wondering if there are unforeseen edge-cases, but also wishing I had it at work. Clunky generics syntax is one of the worst parts of TypeScript, even while generic function types are one of its best parts.
Wow, and side-effects-tracking too! Amazing
I am curious whether some of these checks will be limited by JavaScript's dynamism. Part of why I'm doing mine as a new language is that JavaScript's semantics are just way too flexible to form some of the guarantees I feel like you need for some of this aggressive inference. But now I'm questioning that.
Either way, this is insanely impressive. Definitely not just yet-another-JavaScript-toolchian.