jfecher | 6 months ago | on: Group Borrowing: Zero-cost memory safety with fewer restrictions
jfecher's comments
jfecher | 10 months ago | on: Why Algebraic Effects?
- You wouldn't have to edit the body of the function to thread through the parameter. - The `can Use Strings` part can be inferred (and in Ante's case, it is my goal to have the compiler write in inferred types for you so that top-level definitions can be inferred if desired but still annotated when committed for code review). - Most notably, the `can Use Strings` can be included in a type alias. You could have an alias `MyEffects = can Use Strings, Throw FooError`, etc for the effects commonly used in your program. If your state type is used pervasively throughout, this could be a good option. When you have such an alias it also means you'd just be editing the alias rather than every function individually.
Generally though, while I think the passing around of state through effects can be useful it isn't the most convincing use of effects. I mention it more for "here's another benefit they can have" rather than "here's this amazing reason you should definitely use them for"
jfecher | 10 months ago | on: Why Algebraic Effects?
Not quite. setjmp/lonjmp as they exist in C at least can jump up the call stack but not back down. I mention this at the end of the article but each language implements algebraic effects differently, and efficiency has improved in recent years. Languages can also optimize the effect differently based on how the handler is defined:
- Handlers which are tail-resumptive can implement the effect as a normal closure call.
- Handlers which don't call resume can be implemented as an exception or just return an error value at every step until the function exits the handler.
- Handlers which perform work after resume is called (e.g. `| my_effect x -> foo (); resume (); bar ()` can be implemented with e.g. segmented call stacks.
- Handlers where resume is called multiple times need an equivalent of a delimited continuation.
Another way to implement these generally is to transform the effects into monads. For any set of effects you can translate it into a monad transformer where each effect is its own monad, or the free monad can be used as well. The cost in this approach is often from boxing closures passed to the bind function.
Koka has its own approach where it translates effects to capability passing then bubbles them up to the handler (returns an error value until it gets to the handler).
With just a few restrictions you can even specialize effects & handlers out of the program completely. This is what Effekt does.
There really are a lot of options here. I have some links at the end of the article in the foot notes on papers for Koka and Effekt that implement the approaches above if you're interested.
jfecher | 10 months ago | on: Why Algebraic Effects?
jfecher | 10 months ago | on: Why Algebraic Effects?
jfecher | 10 months ago | on: Why Algebraic Effects?
jfecher | 2 years ago | on: Algebraic effects, ownership, and borrowing
The language does have a basic language server already though! It currently supports inline diagnostics and hover to show type.
jfecher | 2 years ago | on: Algebraic effects, ownership, and borrowing
If anyone's curious, here's how ante addresses these issues:
- It causes memory unsafety: Ante's `shared` references prevent memory unsafety by preventing projecting them into "shape-unstable" types like a vector's element
- Iterator invalidation: This is the previous point in disguise. Since iterating over a shared vector would grab references to its elements - this is prevented since it is shape-unstable. You'd need to clone the elements.
- It's effectively threaded: This is the same bug yet again! Once shared-ness is tracked this becomes a non-issue. Ante is still able to have the static guarantee that this can't happen but does not need to prevent sharing to do so.
- Safe Abstractions: This section is a bit general but it's worth noting Ante still has the ability to have `&own mut t` references if needed. The `swap` function there could use them for example.
Overall the claim that "Aliasing that doesn’t fit the RWLock pattern is dangerous" is fairly rust-centric. It would be dangerous if you had no other restrictions, but we could also adopt different restrictions that still permit aliasing but disallow projection into shape-unstable types instead.
jfecher | 3 years ago | on: Ante: A low-level functional language
jfecher | 3 years ago | on: Ante: A low-level functional language
jfecher | 3 years ago | on: Ante: A low-level functional language
jfecher | 3 years ago | on: Ante: A low-level functional language
jfecher | 3 years ago | on: Ante: A low-level functional language
jfecher | 3 years ago | on: Ante: A low-level functional language
jfecher | 3 years ago | on: Ante: A low-level functional language
jfecher | 3 years ago | on: Ante: A low-level functional language
An ideal solution to me needs to solve these problems. Since there is already a large body of research trying to address this on the static side and failing, I believe it needs to be solved with runtime checks. The specifics of which I'm still exploring but its worth mentioning these would only be necessary to tighten existing lifetimes so one can envision annotations or compiler options to elide these if desired. Lifetime inference in MLKit (and I believe ante as well) tends to speed things up by turning more dynamic allocations into stack allocations, so there is some room there for runtime checks without making the result more expensive than the version with dynamic allocation I believe.
jfecher | 3 years ago | on: Ante: A low-level functional language
jfecher | 3 years ago | on: Ante: A low-level functional language
I'll avoid posting it here but if you do want to follow ante's development the best place is on its discord which is linked on the github page.
jfecher | 3 years ago | on: Ante: A low-level functional language
I'd like to keep this orthogonal to IO or other specific use cases so that it is applicable to any use case users may have rather than tailored to existing ones. You're also correct there is no real logging framework or anything of the kind except print really. Ante is still in a quite early state and there aren't really any substantial libraries to speak of. As-is, interpolation is really just some nice sugar to make some common operations more ergonomic, like f-strings in python.
I think applications that need their own dynamic interpolation requirements should define their own interpolation to handle their specific needs. It would be unacceptable from a performance and predictability standpoint for example to support the example of loading files into a string and have them interpolated at runtime automatically for all file loads.
jfecher | 3 years ago | on: Ante: A low-level functional language
(2): Thanks for the resource, I'll look it over :). I remember seeing a vaguely related note that multicore OCaml used to provide a `Obj.clone_continuation` function but no longer does. Of course, ante's algebraic effects design is rather different so that may not apply anyway. It may depend on the Generator whether it is cloneable or not. Some generators are just functions that can be arbitrarily cloned, but others are closures which may have restrictions in whether their environment is cloneable. Ante's clone story in general needs more work.
Ante's approach manages to blend a similar scheme for safe, shared mutability with Rc. There are some examples on the most recent blog post on its website of it. IMO combined with its shared types it emulates high-level GC'd code very well.