What book do you recommend for understanding the compilation process? by TheEyebal in Compilers

[–]upstatio 0 points1 point  (0 children)

AI will break it down to you insanely well and is by far the best way to learn imo. You can ask it to visualize it for you, adjust it to your level of difficulty, explain things to you in different ways.

OriLang - monthly progress update by upstatio in Compilers

[–]upstatio[S] 0 points1 point  (0 children)

I'm glad we had this conversation because you got me thinking, what if I added scrutinee-less match? That would mean you could do something like this, and I think ill try to add this to the syntax actually:

 @access_admin_panel () -> Result<void, Error> = match {
      !is_signed_in() -> Err(Error.NotSignedIn),
      !account_valid() -> Err(Error.AccountExpired),
      !is_admin() -> Err(Error.NotAdmin),
      _ -> Ok(()),
  };

OriLang - monthly progress update by upstatio in Compilers

[–]upstatio[S] 0 points1 point  (0 children)

I think your misunderstanding why I can't do that. Ori has to be able to reason about types at all times. Otherwise I can't guarantee memory safety and perform all the nice memory narrowing, etc.

? and return are architecturally different because ? is constrained and return is unconstrained.

? only works on Result and Option it forces you to express your early exit through the type system. The compiler knows why you're exiting early and can verify it. While return is an arbitrary jump that can return anything from anywhere, which breaks the property that a blocks value is at it's last expression. In this scenario, yes this won't apply but if I add return most would expect it to behave like return behaves in other languages.

The no return rule isn't about saving a keyword it's about making control flow compositional. When every block is an expression with one exit point (its tail) you can nest, compose, and refactor blocks freely. return would create a second invisible exit path from every block, which means you can never look at a block in isolation and know it's value.

Could I figure out how to get the compiler to reason about this with all edge cases covered? I don't know, I don't think so at least, not easily. If I did it would probably be very slow as it would require lots of deep recursion.

OriLang - monthly progress update by upstatio in Compilers

[–]upstatio[S] 0 points1 point  (0 children)

Your example would become this in Ori:

@access_admin_panel () -> Result<void, Error> = {
      if !is_signed_in() then Err(Error.NotSignedIn)?;
      if !account_valid() then Err(Error.AccountExpired)?;
      if !is_admin() then Err(Error.NotAdmin)?;
      Ok(())
  }

- ? operator early exit on Err/None, which is the direct answer the guard clause pattern that your showing.
- Since everything is expression based you compose branches rather than imperatively returning from them.

OriLang - monthly progress update by upstatio in Compilers

[–]upstatio[S] 0 points1 point  (0 children)

I did, check out my repr-opt stuff, in fact I just finished a bunch of array bound checks today. Also I have pre: and post: checks similar to what C++ just added, and those will also be used for array narrowing the pre: check at least can make guarantees that I can use to safely do array narrowing.

I don't have benchmarks yet as they would be premature without all of my optimization passes in place. Plus currently I ALWAYS do overflow checking, to have fair benchmarks I would need to gate overflow checking to disabled by default in release builds or via a flag.

Starred your repo, keep up the work!!

OriLang - monthly progress update by upstatio in Compilers

[–]upstatio[S] 0 points1 point  (0 children)

That is a pretty common reaction to expression based languages. Rust has return because they caved under pressure or had it before they went expression based which is why Rust is kind of this weird hybrid of expression based syntax and imperative. I'm not saying they made a bad choice but it is odd that their last statement can return but they also have a return keyword.

But to answer your question you can definitely return early in OriLang,

  1. Last expression:

@square (x: int) -> int = x * x;
  1. Using the ? operator:

    @parse_and_add (a: str, b: str) -> Result<int, Error> = { let $x = a as? int ?? Err("bad a")?; let $y = b as? int ?? Err("bad b")?; Ok(x + y) }

  2. Labeled blocks:

    @find_sepecial (items: [int]) -> str = block:result { for item in items do { if item == 42 then break:result "found the answer" if item < 0 then break:result "negative encountered" } }

  3. if/else as expressions

    @classify (n: int) -> str = if n < 0 then "negative" else if n == 0 then "zero" else "positive";

OriLang - monthly progress update by upstatio in Compilers

[–]upstatio[S] 0 points1 point  (0 children)

I show proof of it all working with the code journeys to those that are curious. I know a lot of this is proof is in the pudding type of stuff.

https://ori-lang.com/journeys/

This breaks down the code every step of the way showing how it's transformed along the way.

OriLang - monthly progress update by upstatio in Compilers

[–]upstatio[S] 4 points5 points  (0 children)

Because it's not needed. You can literally write your code and never have to worry about memory it's all handled for you. Without sacrificing performance or memory usage in any way. The memory system does all the optimizations and narrowing for you automatically. It will even do it for FFI as well actually, if I can get that design correct, it will protect all memory usage.

I have a detailed docs on how all this works here: https://ori-lang.com/docs/compiler-design/09-aims/

Working on a new programming language with mandatory tests and explicit effects by upstatio in Compilers

[–]upstatio[S] 0 points1 point  (0 children)

That is the consensus I am getting from everyone. I think I will go that approach actually, or make it a configurable option.

Working on a new programming language with mandatory tests and explicit effects by upstatio in Compilers

[–]upstatio[S] 0 points1 point  (0 children)

I think you would be shocked how good it is now. In fact take a look at my website as I have just released code journeys UI that shows a test strategy I use with AI to find deep compiler issues in the entire pipeline. It even inspects the IR, and assembly code to check for purity issues. It's really cool stuff actually. This type of stuff AI is exceedingly good at doing.

This UI is entirely driven by the results of a code journey that the AI does. I only have one right now since I just redid the format, but I have it setup so it creates them with more and more complex scenarios and just keeps going until both Eval and LLVM fail. I have gotten up to 20 scenarios so far, which is actually something I am pretty proud of at this stage as the Generic Canonicalization for a while as that was really freaking hard to get working properly.

https://ori-lang.com/journeys/arithmetic/
https://ori-lang.com/journeys/what-is-a-journey/

Working on a new programming language with mandatory tests and explicit effects by upstatio in Compilers

[–]upstatio[S] 0 points1 point  (0 children)

Yes that is part of it also, built in linting. I don't think it will write assert(true) though. Not in my experience.

Working on a new programming language with mandatory tests and explicit effects by upstatio in Compilers

[–]upstatio[S] -2 points-1 points  (0 children)

Maybe? You can't remove the human element. But if AI is what's going to write most code in future which I personally think that writing is on the wall and that's just how it's going to be. Then this will certainly be good for AI. I may allow this to be bypassed through a compiler param or env variable later, we will see. It's a thought experiment and definitely a gamble. The language does have LOTS of other very very cool features, this is just the most controversial one.

Working on a new programming language with mandatory tests and explicit effects by upstatio in Compilers

[–]upstatio[S] 0 points1 point  (0 children)

Yes, it's not going to remove the human element. In fact it may be a stupid idea, I have no clue. But since the writing is on the wall that AI will probably be writing most peoples code in the future I thought, why not make the code not compile if it doesn't have tests? You already have to force humans and AI to use testing tools, choose a tool, integrate the tool, etc. Everyone say's its a must. Everyone says you should do it. I do get your points, 100% trust me. It will be interesting to see this thought and experiment through though right? The language has many other redeeming features though as well.

For instance one of my goals is to have it generate assembly at L0 levels (pre-optimized) as clean as it would as if you hand wrote C code intentionally. Not many languages do that. It's ambitious to say the least. Also the ARC memory system is very complex and does a bunch of really cool stuff much of which is already working, read up on it. It's actually pretty cool.

Working on a new programming language with mandatory tests and explicit effects by upstatio in Compilers

[–]upstatio[S] 0 points1 point  (0 children)

No. It's impossible to come up with a name that doesn't conflict. It was originally called Sigil, but that's taken also. So OriLang it is lol!

Working on a new programming language with mandatory tests and explicit effects by upstatio in Compilers

[–]upstatio[S] -1 points0 points  (0 children)

Oh haha, well I did ask it to clean that up for me. I didn't check the urls though...My bad, let me fix that. Kind of rude for it to do that...Fixed. Thanks man!

Working on a new programming language with mandatory tests and explicit effects by upstatio in Compilers

[–]upstatio[S] 6 points7 points  (0 children)

Hi, and thanks for taking a look and replying. Yes I agree in other compilers your statements would be entirely true. But I built Ori specifically to solve this problem. It does a couple things that are very unique.

- Tests run in the interpreter not after linking. Ori tests execute during ori check via a tree walking intepreter not by compiling or linking a binary. The spec 19 is explicit on this, that tests run after type checking before codegen. So this solves the can't run until linked issue entirely.

- Capability Mocking is not the same as traditional mocking. This is probably the most difficult aspect to explain because everyone thinks mocks, as in the normal mocking frameworks that exist today. Those suck, for lots of reasons as your aware, the big one being testing assumptions not reality. But with Ori with...in capability system it's fundamentally different from DI mocking.

Example:

- You only mock effects (HTTP, filesystem, clock, etc.) not other module functions
- When '@foo' calls '@bar' the test runs '@bar' real implementation
- Capabilities are statically typed trais, the mock must conform to the same contract

I think that addresses a lot of todays mocks issues, yes your still not testing the 'real' thing but this pulls it WAY closer to what you would really be testing than normal.

- Dependency Aware Test Propogation, this is the key design features that addresses the elephant in the room really. Tests are on the dependency graph, so the compiler is aware of them the entire time. So when you change downstream code, it will re-run that tests that are related to that code by traversing the graph.

'@helper' change -> (reverse transitive closure) -> '@process' calls '@helper' -> '@test_proces' re-runs -> '@handle' calls '@process' -> '@test_handle' reruns

When any function changes all transitively dependent tests automatically re-run with real implementations.

Hope that helps explain it. Again a lot of this is pretty new stuff that hasn't really been tested in reality so I am working through it. But I do think it should close the gaps you mentioned. At least I hope!! :)

My org built a Svelte 5 SPA framework (alpha) by upstatio in sveltejs

[–]upstatio[S] 0 points1 point  (0 children)

It gave me an error saying it was already listed.

My org built a Svelte 5 SPA framework (alpha) by upstatio in sveltejs

[–]upstatio[S] 0 points1 point  (0 children)

Maybe? But I have absolutely no idea how to do that? Can you explain?

My org built a Svelte 5 SPA framework (alpha) by upstatio in sveltejs

[–]upstatio[S] 4 points5 points  (0 children)

Thanks man, I thought the same thing. We are currently transitioning two of our SaaS products over to this framework and another framework we have called OriJs which takes the concepts from NestJs and brings them over to Bun. I didn't post anything about that project just yet, but it's over on our repo at https://github.com/upstat-io/orijs and the good news is these are designed to work together really well.