5 ms·
As a dev programming in Clojure professionally day to day this complaint (core team not fixing/prioritizing bugs) seems absurd to me. The only example given fo
by lgrapenthin 10y ago
As a dev programming in Clojure professionally day to day this complaint (core team not fixing/prioritizing bugs) seems absurd to me.
The only example given for a bug is not even a bug but undefined behavior triggered by undocumented API usage.
If the author means clojure.spec by "greenfield development" (I don't see what else he could mean) he should really reconsider his complaint since clojure.spec is going to do what he is asking for (throwing a runtime error during development if you use clojure.set with the wrong datatypes).
My impression over the last few years is that the core team became truly excellent in reacting to users needs and reports often instantaneously, especially Alex Miller and David Nolen on the CLJS side.
- mcguire 10y ago"The only example given for a bug is not even a bug but undefined behavior triggered by undocumented API usage." C gets a lot of grief about that sort of thing. It's interesting to see current languages taking the same approach.
- lgrapenthin 10y agoCould you elaborate why? (Haven't done much C) - Is the point of view that it is the languages job to prevent the programmer from relying on uncertainties?
- mcguire 10y agoThe C standards take the rather unique approach of dividing behavior into 4 categories: * standard-defined. You can rely on this; if the code you write is limited to this, you're good to go. * erroneous. The compiler is supposed to give you an error message when you write code like this. * implementation-defined. A particular compiler can do something reasonable with the code. If you write code depending on implementation-defined behavior, you're ok, but your code is not portable. A compiler that doesn't do something reasonable in an I-D situation isn't required to generate an error, IIRC. On the other hand, whatever it does is supposed to be consistent. * undefined. There are explicitly no requirements on the compiler. Whatever it feels like doing is fine with the committee. There's no requirement for a compiler warning or error (and by default, there probably won't be one). The reason for the different categories is twofold: 1. C is a systems language. It's frequently used to do things that depend entirely on the specific hardware the code is running on. The result isn't portable, but in this case, it isn't supposed to be. 2. Performance. The idea is that the compiler can take portable code and produce a program that runs very quickly on the specific hardware. As long as the code doesn't do anything non-standard, the results are guaranteed to be good. An example of the latter is signed integer overflow. (I can't remember whether it's I-D or undefined, but...) If you do MAXINT + 1, the resulting value can differ on different hardware; it could be the most-negative integer, it could be zero, it could cause a hardware trap. Now, the C standard could specify what the behavior should be, say generating a signal that kills the program with an error. But that would be very expensive on hardware that doesn't trap signed integer overflow---it would require a check after every arithmetic operation. So the standard doesn't say what should happen. Another example is poking at memory that isn't allocated by your program (on the stack, or the result of malloc, say). You need to be able to express that for systems programming, but a general standard can't say anything reasonable about it. As a result, C has a lot of unsafe corners where you can unintentionally invoke I-D or undefined behavior. In the first situation, your program will break if you try to port it. In the second, your program might work, most of the time. Or it might toss a runtime error. Or it could generate mangled results. Or it could have a really nasty and embarrassing security hole. As a result, C is regarded as a difficult and (unnecessarily?) dangerous language. And most languages that aren't C and aren't aimed at systems programming try very hard to avoid undefined behavior. Even if you manage to avoid security holes, the bugs resulting from mangled results are a royal pain in the ass to track down.
- lgrapenthin 10y agoThanks for this long and elaborate reply. Clojure tries to put as many user faults into "erroneous" as possible but in the OPs complaint it doesn't have the required information at compile time because it is typed dynamically. This is the fundamental problem with dynamic typing that more problems keep ending up in runtime. Behavioral concerns like security etc. are then often addressed by runtime checks. Clojure avoids those runtime checks everywhere for performance reasons - It is a clear design choice. So your observation seems correct that the "C approach" is used in the dynamic parts of Clojure. Since we don't have a standard, the official documentation is the contract we should rely on and very soon clojure.spec, which is intended as a "standard as data", is going to be.
- lemming 10y agoClojure tries to put as many user faults into "erroneous" as possible I would absolutely disagree with this. Clojure has long had a Garbage-In-Garbage-Out philosophy, which puts it clearly into "undefined" territory. The examples with clojure.set are pretty clearly GIGO in my opinion, but "erroneous" would mean a runtime check and an exception clearly stating which invariant was violated, not returning something totally unexpected. You could argue that it's under "implementation-defined", where the number of implementations is one, but I don't see how you could consider the set operations accepting and returning non-set things as consistent.
- lgrapenthin 10y agoAs I said, the GIGO approach is only used where costly runtime checks would be the alternative. Macros check their arguments at compile time a lot.
- lemming 10y agoI disagree on both points there, I don't think that an instanceof check is that costly compared to many of the other performance hits we're willing to accept with Clojure for saner behaviour. For example, persistent data structures are slower than mutable ones, but I'd never go back to using mutable ones in most cases. Why is one performance hit acceptable for better behaviour and the other isn't? I also disagree about macros, too - I spoke at the conj last year about that, and that talk seems to have been at least part of the motivation for developing spec. I hope that things will improve as spec becomes more widely used, but right now the situation for macro error messages is pretty bad.
- MustardTiger 10y agoProgrammers are still humans at this point. Humans make mistakes. It is helpful to have software executing on computers prevent us from making mistakes rather than making it easier for us to make mistakes.
- msbarnett 10y agoDynamic languages don't really have any choice in the matter -- it's always going to be possible to pass an unanticipated type to a function, whose results may or may not be surprising or sensible
- dlandis 10y ago> The only example given for a bug is not even a bug but undefined behavior triggered by undocumented API usage You only saw one example bug? He linked to 5 tickets in the section "show stopping bugs remain untouched".
- lgrapenthin 10y agoIf you look into the tickets you'll find that they aren't bugs but feature requests. Labeling them "show stopping bugs" is even more misleading than the now prominent clojure.set complaint.
- dkersten 10y agoIf the author means clojure.spec by "greenfield development" (I don't see what else he could mean) EDN, Transit, reducers, transducers, clojure.spec (I'm not saying any of these things are bad or anything, just pointing out that there was a lot of green field development done in the past few releases)