3 ms·
As they should be. I object to doing what a computer can do for me (in programming), and manually creating separate versions of functions that are identical up
by throw10920 2y ago
As they should be.
I object to doing what a computer can do for me (in programming), and manually creating separate versions of functions that are identical up to async absolutely falls into that category.
- Rapzid 2y agoThey have different signatures because they return different things.
- goatlover 2y agoNot in languages like Ruby.
- Rapzid 2y agoSpicy!
- throw10920 2y agoThe difference between returning a Foo and Promise<Foo> is utterly irrelevant in this case because the computer is capable of automatically handing the difference.
- lmm 2y agoSo use a language that knows how to be polymorphic over async. Just like you don't want to have to write one version of sort() for each possible array element type, but the solution isn't to make all array elements untyped, the solution is to have a language that can abstract over that.
- mmaniac 2y agoCan you give an example of a language which is polymorphic in this way and how that looks?
- lmm 2y agoHaskell or Scala are the immediate examples. The idiomatic way to write async-style functions in those languages tends to be do notation or for/yield style. E.g. transformFile = do { x <- readFile(...) y = process(x) z <- writeFile(...) } is the equivalent of something like: async transformFile = { x = await readFile(...) y = process(x) z = await writeFile(...) } In Haskell you write exactly the same code when readFile and writeFile are async, or when they're polymorphically async-or-not, your function will just implicitly be as polymorphic as it possibly can be based on the functions it's calling. In Scala you need an explicit type parameter if you want to be polymorphic: def transformFile = for { x <- readFile(...) y = process(x) z <- writeFile(...) } yield () def transformFile[F[_]: Monad] = for { x <- readFile(...) y = process(x) z <- writeFile(...) } yield () The first example is always async, the second example is polymorphic (it's calling readFile[F] and writeFile[F], but those get inferred).
- mmaniac 2y agoAh I've got it. Async is a monad and the function is just polymorphic over Monad m. In the sync case m is Identity. Can you point me in the direction of some libraries which offer functions like these?
- lmm 2y agosttp (HTTP client), http4s (HTTP client/server), quill (database access), fs2 (streaming data processing), I have some vague memory of a gRPC implementation. A lot of stuff that does async in Scala tends to be written in this style because it's almost no extra cost compared to writing it in strictly async fashion.
- throw10920 2y agoYeah, that's the correct solution. I'm not arguing for the solution, I'm arguing for the problem, because a lot of people seem to think that the problem isn't real.
- lmm 2y agoSure, but if you put it that way it tends to come across as wanting to not track the distinction at all. Like if you said it's good that values are untyped in Ruby because to write a collection type in C you have to reimplement it for every different type of collection you want: yes, but that doesn't mean values having types is bad, it just means you need polymorphism.