3 ms·
> Now you can update and test in batches without having to refactor 1000s of lines in one go. If a change in a datatype forces you to update 1000s of LoCs, you
by ac 14y ago
> Now you can update and test in batches without having to refactor 1000s of lines in one go.
If a change in a datatype forces you to update 1000s of LoCs, you are doing something wrong.
- Chirono 14y agoHmmm, you're probably right. I had in mind something like GenStgExpr[1] that make up the STG type in GHC. I'd imagine with all the optimisations, serialization and code-gen that is based directly off that data structure, any significant change will have at least 1000 line nock-on effect. Perhaps I'm over estimating though. I'd guess it comes down to the size of the project. 1) https://github.com/ghc/ghc/blob/master/compiler/stgSyn/StgSyn.lhs https://github.com/ghc/ghc/blob/master/compiler/stgSyn/StgSy...
- ac 14y agoGHC is a bit of a pathological case, which doesn't make it less valid. I wouldn't really dare to estimate how much refactoring you need to do if you change, say, one constructor of GenStgExpr, primarily, because I don't know the GHC codebase. In my work I have had instances when I had to change datatypes drastically and refactor the code accordingly. I'd say, in all cases the type system was helpful -- I just go to every error location (very easy with, e.g., ghc-mod), and it's invariably a pattern-matching case, so I fix a bit of code here and there (20 LoCs at most) and it all worked. But the thing is, of course, if you change your datatypes all the time even these kind of small changes will soon become tedious. But then if one programs in Haskell in a hacking mode ("meh, let's try throwing this thing in, maybe it will miraculously start working") -- it just won't work. Haskell requires one to think well, before programming -- that's why I love it. I think, in the end it saves time. Another problem might be that the datatype you are refactoring is fundamental to your program and is used in most modules -- I think it's just short-sighted design. GHC, for example, has several different program representations (Haskell, STG, Core, maybe some others), so a change to one representation would only affect a part of the compilation pipeline (namely, the translation to and from that rep and the associated optimisations/analyses). But if you really need such a fundamental mega-type that will change during the lifetime of the program, why not write an easier to manage interface to it? Either use the record syntax or write setter/getter functions by hand. Just $ my $0.02 where my=id
- Peaker 14y agoA common purpose of changing something is fixing something that was done wrong. Consider, for example, fixing the Monad class to subclass Applicative. Or to remove the "fail" or (>>) methods. This would incur a change to many thousands of lines of code. Similarly, a core/base type of a whole project can be used across an entire codebase. It is possible to discover desirable changes to such a base type, and it will incur a huge change.
- ac 14y agoYes, things like changes to core library types are disastrous. But, if you have a core data-type that you know will change and you haven't isolated the impact of these changes by, say, using accessor functions, you're the one to blame. See my long-ish reply in the sibling thread for details. And, yeah, I've learned all this the hard way :(
- Peaker 14y agoOne of the nice things about Haskell, is that changes that are disastrous in other languages are not necessarily disastrous. I think any notion of blame is really irrelevant here. The discussion was whether this kind of feature is useful. I think you implied it wasn't, because the cases it were useful in are those in which you did something wrong. But that does not follow at all. It is very possible one is to blame for a horrible mistake in the codebase, and that it still needs and can be fixed. This feature makes that fix cheaper and more practical.
- ac 14y agoI mentioned earlier that I found the GHCI use-case extremely useful (see my root comment after EDIT). But I have an issue with the uses like turning off the typesystem and have the project compile just so that you could feel good about yourself. I don't believe that would help your bottom-line. But, as long as I don't have to work with you or your software, I don't care. And, large refactoring efforts are necessary in every complex and evolving system, irrespective of your language of choice -- but turning off your type checker or any other static guarantees isn't the way to go. Programming is hard enough even in the presence of type-checking and automated analyses -- why make it even harder? Anyway, I feel like I've made my point enough -- take it or leave it.