Live data from Hacker News

Effect Systems vs. Print Debugging: A Pragmatic Solution

blog.flix.dev

31–40 of 49 posts

Re: Effect Systems vs. Print Debugging: A Pragmatic Solution

#31

> Hence, when the compiler is run in production mode, we disable the lie that allows the implicit Debug effect. As a result, using dprintln in production mode causes a compilation error. The team can’t seem to make up its minds of the language is intended for high performance or not. They talk about the importance of purity for automatic optimizations but in the real world there’s all sorts of practical reasons for n…

This seems like an uncharitable reading of the post. > They talk about the importance of purity for automatic optimizations but in the real world there’s all sorts of practical reasons for needing to debug production compiled code I imagine they're talking about their defaults. One can commonly reconfigure how different build profiles work. > Also blaming the users of your language for your language not being able to…

> What do you mean turning off the fuel for the engines crashes the plane? I thought you said this was a safe airplane?!

Things like this - they're painting users of programming languages as the ones being unreasonable.

> I imagine they're talking about their defaults. One can commonly reconfigure how different build profiles work.

From the article:

> We don’t want published packages to (a) lie to the type and effect system, or (b) contain print debugging statements > As a result, using dprintln in production mode causes a compilation error.

There is no documentation about the existence of build profiles or how they might work. I think you're reading too charitably.

Re: Effect Systems vs. Print Debugging: A Pragmatic Solution

#32

Earlier quoted context omitted.

And yet modern optimizers don’t actually seem to have a problem with a transformation like that as you must know. Try list.iter().filter(|x| x>5).count() in Rust And yes, Rust doesn’t have an effect system yet, but others have mentioned Haskell and how it handles tracing and logging and the limitations of effect systems interplaying with such things.

It was a simple example; whether a specific optimization applies is very tricky. We have to look at the details. When can Rust move or eliminate a binder? Does Rust support automatic parallelization? What happens if you use unsafe blocks to lie to their type and ownership system? I think many of the same issues will surface. To be me, the interesting question is: What happens when you lie to the type (and effect or o…

> Does Rust support automatic parallelization

No, and there's no indication that automatic parallelization is at all worth the effort vs having the author explicitly annotate which things need parallelization (e.g. Rayon is drop-in for many tasks where you know you'll need it). Otherwise you're at the mercy of heuristics baked into the language which in practice never work out well and also slow down the non multithreaded use-cases.

> To be me, the interesting question is: What happens when you lie to the type (and effect or ownership) system?

As others have said, just having the print get elided if the operation gets optimized out would be fine. That's what Haskell does. It's a weird choice to look at the challenges of effect systems and conclude the effect system idea is perfect it's the programmers who are wrong and not that the effect system has gaps that can't be addressed and solve it in other less surprising ways.

Re: Effect Systems vs. Print Debugging: A Pragmatic Solution

#33
post #25

Is there a target use case(s) for this language, at least initially? It seems to focus on programming in a platform-independent sense, but where is it most likely to actually succeed? Are there particular OS’s or other languages that they try be particularly compatible with?

It runs on the JVM, so I suppose that's the "OS" it's compatible with and Java is the language. It's still mostly academic AFAICT, but I could see experimenting with it for backend stuff.

Re: Effect Systems vs. Print Debugging: A Pragmatic Solution

#34
post #26
post #2

I wonder if this will wind up being a category of problems and the solution is a separate "system" set of effects (effectively `({user}, {system})`) or if this one-off extension is all that will be needed. Either way, extremely well explained both in motivate and implementation!

The other major use case that leaps to mind is "observability"; I want to be able to poke a metric without the function becoming impure, since it is not uncommon for something deep down the call stack to poke a metric and I don't want it to propagate up the stack. You can also make a case for logging that isn't just debug logging. Propagating up a new effect just because some deep function needs to push a log is not…

100% well said! Exactly how to handle log/print/metrics (as results/returns from functions) has been on my mental back burner for years.

It's proper (but goofy) to pass in a `logger` object to every function, but the practicality of plumbing a "logger" everywhere is disgusting. There's a ton of value to be able to "capture" what was logged by a function, but as you mentioned with "metrics", the invasiveness of plumbing a metrics object "through" your code is really gross.

Maybe a straw man syntax like:

   this.__classHooks__.logger
      = new AbstractLogger(...)
   this.__classHooks__.metrics
      = new AbstractMetrics(...)
...like a puzzle piece, if the container (parent object) wants to "attach" to the exported interface, it can kindof dependency injection, otherwise logs and metrics might fly off into the void.

Re: Effect Systems vs. Print Debugging: A Pragmatic Solution

#35
post #9

Honestly a pragmatic solution would be to have printing to stderr (debug print, logs, whatever) not be an "effect". then as an added benefit if its context is elided out in an optimization you know.

This is similar to what Haskell has with trace[1]. It pretends to be a pure function (so it doesn't need the IO monad), but prints to stderr. [1] https://hackage.haskell.org/package/base-4.21.0.0/docs/Debug...

And, just like tfa alludes, it is awkward because of laziness; in non trivial scenarios it can be quite surprising how your trace isn’t tracing.

This is bc of non strict eval in Haskell, but still the core is that the lang is designed to not eval stuff when it’s not necessary.

Re: Effect Systems vs. Print Debugging: A Pragmatic Solution

#37

Cool idea to "type" side effects I'm curious what other languages are trying to achieve such?

AFAIK the first somewhat widely-known language to do this was Haskell (through libraries). I'm not 100% clear on the entire history, but I think it goes something like: 1. Initially there was no way to do effects in Haskell, everything was pure. 2. Then it was realized that IO can be modeled with monads, so the IO type and do notation were added. 3. Gradual realization that monads can be used to also constrain effect…

> I'm not 100% clear on the entire history, but I think it goes something like:

You can see my talk "A History of Effect Systems" for a synopsys of the history. I gave it at Zurihac this year. It's very close to the history you gave (though I think point 1 is not right: Haskell always had a way to do IO)

https://www.youtube.com/watch?v=RsTuy1jXQ6Y

Re: Effect Systems vs. Print Debugging: A Pragmatic Solution

#38

To do this you made the Debug effect a special case in the compiler. Won't users want to create their own special effect types? Could these special effects be expressed within the language itself instead of being compiler builtins?

We can certainly extend it to a language feature-- if there are good use cases.

Do you have some specific special effects in mind?

Re: Effect Systems vs. Print Debugging: A Pragmatic Solution

#39
post #12
post #7

Earlier quoted context omitted.

> I wonder if this will wind up being a category of problems and the solution is a separate "system" set of effects (effectively `({user}, {system})`) or if this one-off extension is all that will be needed. It already is, kinda. In my practice very often you have global singleton values that are either defined as static variables, or passed as arguments to nearly all functions in a module. Since implicit presence of…

> Thus you might design a module that has implicit Logger and Database effects in all its functions. Logging does seem like a very similar case to debugging, only that you expect to leave it on in production. On the other hand an implicit Database effect kind of defeat the point of an effect system. I think the key is that Debug and Logger effects don't really affect the rest of the code - if you remove all debug/log…

> Logging does seem like a very similar case to debugging, only that you expect to leave it on in production

In a lot of logging systems, debug is one of the common levels of logging. I'm not even convinced that the term "debug" is unambiguous to clearly refer to something that's not a subset logging. Presumably the difference is intended to mean things printed that are unconditionally going to stdout rather than into some system that might change the output location and filter/annotate things, but I have to imagine that it might just make more sense not to have separate models for them at all

Re: Effect Systems vs. Print Debugging: A Pragmatic Solution

#40

To do this you made the Debug effect a special case in the compiler. Won't users want to create their own special effect types? Could these special effects be expressed within the language itself instead of being compiler builtins?

We can certainly extend it to a language feature-- if there are good use cases. Do you have some specific special effects in mind?

Disclaimer: I don't know much about this programming language or about Effects, so there may be a better way to do this already

something I'd sometimes like to do when I'm profiling complex code will be to have an (essentially) global variable tracking the sum of how long a function took to execute over all invocations.

I am guessing that mutating the global counter would count as an effect, and I wouldn't really want to add the effect all the way through the call graph. I think this is something where the handling ought to be similar to how you're handling Debug.

Post reply on HN