3 ms·
Well yeah, because a logging statement in production can fail (i.e. network connection drops). The type system forces you to deal with that fact instead of lett
by pka 8y ago
Well yeah, because a logging statement in production can fail (i.e. network connection drops). The type system forces you to deal with that fact instead of letting you write code that e.g. brings down your server unexpectedly because of some random log call.
Many would consider that a feature, but if you want to #yolo it anyway, like in most other languages, just use trace in prod and call it a day.
- yogthos 8y agoThe type system forces you to solve this problem in a very specific way by structuring your entire app around pushing IO to the edges. There are plenty of other ways to address the problem that work perfectly fine in practice. For example, you can specify what should happen is IO fails in your logging configuration. This handles the exceptional case consistently and in a single place without forcing you to structure your whole app around it. What's more is that there really isn't a sane way to recover from such a catastrophic failure. If your database goes down, or you lose a disk, the only thing you can do is shut down the app. It's not like it's gonna keep humming along with the logging failing silently. This kind of hyperbole that your either solve all problems via the type system or #yolo is precisely what makes Haskell community so toxic in my opinion.
- antidesitter 8y agoWhat makes you think the Haskell community is toxic? I usually hear the exact opposite.
- yogthos 8y agoI find that the Haskell community is very friendly as long as you buy into their approach to solving problems. However, my experience is that if you question the effectiveness of static typing, or ask for evidence in support of the claimed benefits you'll get a very hostile reaction. The comment above where pka snidely claims that using any alternative to types amounts to yolo is quite representative. He outright dismisses that any valid alternatives are possible, and he indirectly claims that people using other methods are being unprofessional and are cutting corners. That amounts to toxic behavior in my opinion.
- hota_mazi 8y agoFacts have been presented to you multiple times but your adoration of Clojure just makes you dismiss them outright. People who claim dynamic type systems are superior to static ones can be dismissed in much the same way flat earthers can because both choose to dismiss evidence they find inconvenient.
- AlexCoventry 8y agoI was going to suggest that yogthos may just be thinking of that one guy who converted from clojure to haskell and had a convert's typical evangelical zeal in #clojure, but then I read your reply. Ironic.
- bmurphy1976 8y agoYou know he can be wrong about some things but still make a valid point about others. How do you think this reads in relation to his primary claim about the Haskell community? > People who claim dynamic type systems are superior to static ones can be dismissed in much the same way flat earthers can because both choose to dismiss evidence they find inconvenient. Seriously. This only feeds into his narrative.
- dang 8y agoThis comment breaks the site guidelines in multiple ways. No personal attacks, and no programming language flamewars, please, on Hacker News. https://news.ycombinator.com/newsguidelines.html https://news.ycombinator.com/newsguidelines.html
- pka 8y ago> However, my experience is that if you question the effectiveness of static typing, or ask for evidence in support of the claimed benefits you'll get a very hostile reaction. That's an interesting thing to say, seeing how representative figures of (specifically) the Clojure community get really defensive really quickly once somebody questions the effectiveness of dynamic typing - which I specifically didn't do. > He outright dismisses that any valid alternatives are possible I was merely dismissing your incorrect claim about logging in Haskell. And yes, not taking advantage of the type system when you are already programming in a language with a type system amounts to #yoloing it, in my opinion. Doing the same in other languages is fine, since you don't have another option really.
- dwohnitmok 8y agoI hope you haven't gotten the impression that it's types or nothing when it comes to Haskell (although given the bleeding edge of the community's tendency to asymptotically approximate dependent types with GHC extensions I can see where the sentiment comes from). Haskell is certainly not expressive enough to push all invariants to the type system and sometimes you just record the possibility of an error in the type and then just do a runtime check. It's a similar phenomenon to Lisp beginners who discover macros and decide to macro everything and anything. That being said I don't think the "well just let it blow up" is a good one either. It works in a certain subset of cases (when you know that your program can only do certain things and you have a useful supervisor such as in Erlang). I think that philosophy is part of why Clojure has historically had problems with error handling especially in its own toolchain (e.g. its rather cryptic error messages) and still doesn't really have good tooling or patterns for it (e.g. I think nil punning is a dangerous pattern, throwing useful and specific exceptions feels unidiomatic with the need for gen-class, and it doesn't seem like other solutions have garned much mind share). Spec is gaining momentum, but seems to still be spewing mysterious messages that require some familiarity to decipher in some cases (although last I checked things seemed to be on the upswing and I'm quite out of date with Clojure at this point). Even when your app fails you still want to do leave a human readable message and then e.g. log metrics on what kind of error it was and metadata about the error to some supervisor service rather than just let whatever the deepest exception was filter through. "Our authorization request to the database failed with an authorization error and this is the metadata" saves a lot of time compared to an NPE, especially when you're the maintainer and not the writer of the code in question. The Elm community I think is the gold standard of taking the error path as seriously as the success path when it comes to their tooling and it really pays in my experience when I use it.
- yogthos 8y agoIn the specific case letting it blow up is really the only thing you can do unless the whole architecture is designed around it. However, my point was that there are many ways to handle that type of problem, and I've seen no evidence to suggest that using types is the most effective one in practice. When it comes to error messages, I would argue that Haskell ones are no better than Clojure. If anything they're often even less useful because of how generic they tend to be. All you'll know is that A didn't match B somewhere, and figuring out why is an exercise left to the reader. Personally, I like nil punning and I find it works perfectly fine in practice. My view is that data validation should happen at the edges of the application, instead of being sprinkled all over business logic. If you know the shape of the data, then you can safely work with it. The idea of doing validation at the edges also applies to functions, if nil has semantic meaning then the function should handle it before doing any nil punning. If it doesn't then it should be safe to let it bubble to a place where it does. The idiomatic solution for throwing errors in Clojure is to use ex-info and ex-data as seen here https://clojuredocs.org/clojure.core/ex-info https://clojuredocs.org/clojure.core/ex-info Spec errors are not really meant for human consumption, but there are libraries such as expound https://github.com/bhb/expound https://github.com/bhb/expound that produce human readable output. My team is using it currently, and we're very happy with it. I do think that more could be done in the core however, and it does appear that 1.10 will make some improvements in that department. In general, the impression I have is that Clojure errors aren't poor due to technical reasons, but simply because the core team hasn't considered them to be a priority until recently.
- topmonk 8y agoyou don't need to do either. just run performUnsafeIO if you really want to spit out log statements randomly. I like having to do logging the Haskell way, actually. it allows for more coherent and easier reuse. What if want to reuse some code, but do logging in a specific way? By allowing the caller to decide where logging goes you can readily accomplish this.
- lmm 8y ago> For example, you can specify what should happen is IO fails in your logging configuration. This handles the exceptional case consistently and in a single place without forcing you to structure your whole app around it. In Haskell you can write a function that does "unsafe" logging and handles exceptions if that's the behaviour you want. You can even make that function change its behaviour based on a config file if you really want to. > What's more is that there really isn't a sane way to recover from such a catastrophic failure. If your database goes down, or you lose a disk, the only thing you can do is shut down the app. It's not like it's gonna keep humming along with the logging failing silently. That sounds like an argument for including the IO effect in your whole program's structure like people usually do in Haskell, no? If you change a function that doesn't access the disk (e.g. something that just grinds out a mathematical computation) into one that does access the disk by adding logging, you have a new set of possible failure scenarios to be aware of and want that to be visible. I appreciate that this all sounds very theoretical but it can easily lead to real-world failures. I've seen "impossible" control flow because of an unanticipated exception in a function that didn't look like it could exception cause production issues. I can easily imagine e.g. leaving data in a remote datastore like redis in a supposedly impossible state because your redis-error-handling code tried to first log that an error had occurred and that logging then failed because local disk was full. > This kind of hyperbole that your either solve all problems via the type system or #yolo is precisely what makes Haskell community so toxic in my opinion. Every time I've bypassed the type system I've come to regret it, usually when it caused a production issue. It's not hyperbole, it's bitter experience.
- yogthos 8y agoAll I can say is that we clearly have divergent experiences here. I've worked with statically typed languages for about a decade, I used Haskell specifically for about a year. I've since moved to Clojure, and I've been using it for the past 8 years professionally. My experience is that the team I work on is much more productive with Clojure than any static language we've used, and we have not seen any increase of defects in nearly a decade of using the language compared to similar sized projects we've developed previously in statically typed languages like Java and Scala. If dynamic typing was problematic we would've switched back a long time ago.
- gowld 8y agoIn other languages, if the logging facility fails, you can simply continue running the program without logging. This works reliably enough across the world for many years that no one worries about log statements in production being unsafe.
- dwohnitmok 8y agoSome people in the Haskell community think so too. See e.g. http://hackage.haskell.org/package/simple-logger-0.0.4/docs/Control-Logger-Simple.html http://hackage.haskell.org/package/simple-logger-0.0.4/docs/... where you log pure code without introducing a change at the type level.