3 ms·
This doesn't give a focused explaination on why. I don't see how dependency injection is a benefit when languages without algebraic effects also have dependency
by charcircuit 1y ago
This doesn't give a focused explaination on why. I don't see how dependency injection is a benefit when languages without algebraic effects also have dependency injection. It doesn't explain if this dependency injections is faster to execute or compile or what.
- yen223 1y agoThe way dependency injection is implemented in mainstream languages usually involves using metaprogramming to work around the language, not with the language. It's not uncommon to get errors in dependency-injected code that would be impossible to get with normal code. It's interesting to see how things can work if the language itself was designed to support dependency injection from the get-go. Algebraic effects is one of the ways to achieve that.
- vlovich123 1y agoDon’t algebraic effects offer a compelling answer to the color problem and all sorts of related similar things?
- threeseed 1y agoBut they also introduce their own color-like problems. For example with Scala we have ZIO which is an effect system where you wrap all your code in their type e.g. getName(): ZIO[String]. And it doesn't matter if getName returns immediately or in the future which is nice. But then the problem is that you can't use normal operators e.g. for/while/if-else you need to use their versions e.g. ZIO.if / ZIO.repeat. So you don't have the colour problem because everything is their colour.
- OtomotO 1y agoBut that's only a problem if it's a library and not done on the language level?!
- threeseed 1y agoBut in the research languages listed they still are colouring function types. So it doesn't seem to matter whether it's a library or in the language. Either everything is an effect. Or you have to deal with two worlds of code: effects and non-effects.
- vlovich123 1y agoMaybe but even if that's the case, you've now got just plain and colored vs before you'd have plain, color A, color B, color C if you go beyond just async as the only other color (e.g. whether you're accepting something by reference or value, whether it's a mutable reference, whether or not the function is compile-time, etc etc etc). Still seems better to me if you collapse colors >= 1 into a single language system.
- sullyj3 1y agoFunctions can be polymorphic in their effectfulness, so the coloring problem isn't. Functions only become incompatible where you've made them incompatible on purpose - the whole point of annotating functions' effectfulness is to statically know you're not accidentally invoking particular effects where you promised you wouldn't.
- jfecher 1y agoDeveloper of Ante here. Functions in languages with effect systems are usually effect polymorphic. You can see the example in the article of a polymorphic map function which accepts functions performing any effect(s) including no effect(s). For this reason effect systems are one of the solutions to the "what color is your function" problem.
- charcircuit 1y ago>It's interesting Which is why I was asking for that interesting thing to be written in the article on why it would better.
- cryptonector 1y agoIt's the same as with monads: 1) Testing. Write pure code with "effects" but, while in production the effects are real interactions with the real world, in testing they are mocked. This allows you to write pure code that does I/O, as opposed to writing pure code that doesn't do I/O and needs a procedural shell around it that does do the I/O -- you get to write tests for more of your code this way. 2) Sandboxing. Like in (1), but where your mock isn't a mock but a firewall that limits what the code can do. (2) is a highly-desirable use-case. Think of it as a mitigation for supply-chain vulnerabilities. Think of log4j. Both of these are doable with monads as it is. Effects can be more ergonomic. But they're also more dynamic, which complicates the implementations. Dynamic features are always more costly than static features.
- charcircuit 1y agoAgain you are listing things that are possible but not explaining why it's better to do it via algebraic effects as opposed to the alternatives. For example if you were in a meeting with Oracle to try and convince them to invest 100 million dollars for adding algebraic effects to Java and its ecosystem how would you convince them it would be providing enough value to developers to justify it over some other improvement they may want to do. For example, "Writing mocks for tests using algebraic effects is better than using jmock because ..."
- cryptonector 1y agoThe only reason I can think of -but I'm not the right person to ask- is ergonomics, that in many cases it might be easier to push an effect handler than to build a whole monad or whatever. Elsewhere in this thread there's talk of effects solving the color problem.
- threeseed 1y agoTake the following requirement: "A user has made an API call. I want you to in parallel race two concurrent tasks: check if the data is in (1) cache and (2) database. Whichever returns fastest return to the user. Otherwise kill the other task mid-flight and make sure the connection resources for both are cleaned up". This is trivial with an effect systems like ZIO and it will work flawlessly. That's the benefit of effect systems. Use cases like this are made easy. But now with JVM Virtual Threads there are frameworks like Ox: https://github.com/softwaremill/ox https://github.com/softwaremill/ox which allow you to achieve the same thing without effects. And how many times do you really need that sort of capability ?
- iamwil 1y agoBecause Algebraic Effects are unfamiliar, we explain a part of it with something that's familiar to most developers. This is just like the story of the blind men with the elephant. The elephant (algebraic effects) is a whole other different beast, but to help the beginner understand the first parts of it, we say the truck is like a snake (resumable exceptions) or that the ear is like a fan (dependency injection). Algebraic effects are a new type of control flow. When an effect is raised, the handler (defined further up the call stack) has several options: - handle the effect and resume the computation where the effect was raised. - handle the effect, but resume the computation multiple times back to where the effect was raised. - decide not to handle the effect, and just exit, at which point the execution resumes right when the handler was called further up the stack, and everything executed since then is as if it never happened. This is a way of doing back tracking. In addition, what's algebraic about algebraic effects is that they usually come in a group, and are designed with a compositional algebra, so you can safely compose them in different ways. A common one is commutativity, so it doesn't matter what order you execute them in. Of course, not all algebraic effects have commutativity, as that has to be designed by the implementer. Monads are different in that they often don't compose without monad transformers, so that can be finicky. Hence, with all these things together, you can use them to implement control flow in other languages that are typically baked into the language, such as exceptions, coroutines, generators, async/await, probabilistic programming, backtracking search, dependency injection. You might also invent your own! But most commonly here, we use them to separate the *intent* to do a side-effect from the actual execution of the side-effect. That way, side-effects are controlled, and it becomes easier to reason about our code.