4 ms·
In a language and type system where the compiler infers all of the intermediate types, no. The way effect systems are typically added to languages without this
by AaronFriel 6y ago
In a language and type system where the compiler infers all of the intermediate types, no.
The way effect systems are typically added to languages without this level of type system is that the effect "fails". Like making a database call in Python without "with use_database(...):" that provides the database context. In those languages and with those effects, typically the default behavior is the effect's methods are always available, but may either be a no-op/return a nullish value or throw an exception.
As an example, the way tracing works on Node.js is that you have to explicitly declare a span (or use a plugin for a framework which does that for you) and inside that span, you can do something like getSpanId() and it'll return a value. Outside a span, it returns null.
The worst case scenario is you have a language and framework where it's both difficult to annotate the types and difficult to provide some ambient context. In those cases, you're back to (essentially) passing your trace span, your logger, etc as arguments to every function again. Not ideal.
- dan-robertson 6y agoIn every language I’ve used where types can be inferred, almost everyone writes down the types of their top level functions (or at least the functions that are exposed to clients). I don’t think this is really a good counter argument. The only ways I know of to reliably make this kind of change (or just about any nontrivial change) to an interface are increasing version numbers and letting clients suffer or having a monorepo and fixing all the clients yourself
- AaronFriel 6y agoIn Haskell, it's the norm I think to do both: let the compiler infer the type and then add the inferred type to the code. This locks in compatibility.