4 ms·
Yes, you need to understand a bit of APL to grok the style, but I don't know why it bothers people so much. I'm guessing because it involves people actually usi
by scottlocklin 7y ago
Yes, you need to understand a bit of APL to grok the style, but I don't know why it bothers people so much. I'm guessing because it involves people actually using the macro system for something interesting. Somehow lisp gets a pass.
Personally I think stuff like the DO macro (F/Fj in this code base https://bitbucket.org/ngn/k/src/master/k.h https://bitbucket.org/ngn/k/src/master/k.h) should be used everywhere to the extent it is part of the C standard. If compilers were aware of it, there are significant optimizations which could be made. It's dirt simple and saves considerable typing and eliminates lots of potential for error.
- msla 7y ago> Somehow lisp gets a pass. OK, which is more readable: (setf (car lst) "value") Or: (rplaca lst "value") I think the one which allows me to learn "setf's destination is the first parameter" and forget the rest is easier by far. setf is glorious macrology: It allows people to write arbitrarily complicated datatypes and have assignment just work, reliably. But the problem with this code isn't the macros. It's the fact the author types like they're being charged by the character and taxed for whitespace. The macros are amazing to the extent they allow this sort of thing. Blaming them for it is wrong, but judging by the only standard that matters, readability, this is not a good coding style.
- RodgerTheGreat 7y agoYour example neatly demonstrates that your definition of readability is based on familiarity. What does variable assignment have to do with the Contents of Address Register, anyway? In the absence of familiarity, minimizing the number of moving parts and factoring out repeated patterns still has intrinsic value for aiding understanding.
- msla 7y ago> Your example neatly demonstrates that your definition of readability is based on familiarity. What does variable assignment have to do with the Contents of Address Register, anyway? I explained myself right below my examples. > In the absence of familiarity, minimizing the number of moving parts and factoring out repeated patterns still has intrinsic value for aiding understanding. And now you're repeating what I said.
- jodrellblank 7y agoIt's the fact the author types like they're being charged by the character and taxed for whitespace. I dunno about you, but I have very little working memory in my head, just a few items, and only one focus of attention with a narrow field of view. I can’t read that style of code, but opening a traditional codebase with part of the code here using lots of symbols to achieve a tiny amount of work and the next piece of work is four screens away, using a lot of symbols to achieve a small amount of work, it’s like declaring legalese as the most readable kind of English because it bloats so big it must be readable. judging by the only standard that matters, readability, this is not a good coding style What about composable idioms and conventions which let you do a lot of data transforms with a little attention and time? What about a small amount of code to maintain and refactor? If this style saved you ten lines it might not help but where’s the cutoff that you’d start to be interested - if it saved you 50% of the work? 75%? 99.999999%? If “big count per line of code is constant” this ought to be an exceptionally low bug style, right? What about having less code to demonstrate correctness of? What about having little code to throw away and rewrite if you don’t like it, leasing to a faster refactoring cycle time and a better expression of your intent after s set time? Or leading to readability simply being less important because the cost of rewriting 50 lines from scratch is so much lower than rewriting 10,000 lines from scratch? Or if you’re writing documentation and there’s an order of magnitude less code to write about? Or if you should write as many lines of test code as real code, and there’s an order of magnitude less code to test? The whole style isn’t just “golf the character count”, but “collapse down the size of everything so one human attention covers a lot more of it, like zooming out to get a higher overview”. Crossing down from several files to one file is a phase transition, crossing from one long file to one screen, is.
- msla 7y ago> I dunno about you, but I have very little working memory in my head, just a few items, and only one focus of attention with a narrow field of view. Right. Which is why readable, mnemonic names are so important. Single-character names are good for array indexing, because their scope is so small you can see the whole region they're used in a fraction of a screen (usually) but variables which get used over a larger fraction of the codebase need names which explain what and why they are. > What about composable idioms and conventions which let you do a lot of data transforms with a little attention and time? Great. That doesn't preclude meaningful variable names. > What about a small amount of code to maintain and refactor? If this style saved you ten lines it might not help but where’s the cutoff that you’d start to be interested - if it saved you 50% of the work? 75%? 99.999999%? Great. That doesn't preclude meaningful variable names. > If “big count per line of code is constant” this ought to be an exceptionally low bug style, right? If that's true to an unlimited extent, IOCCC programs should be nearly self-debugging, with how short they are. > What about having less code to demonstrate correctness of? Testability is about each bit of code doing one thing, not doing ten things in one line. You can test one thing. If you try to test ten things at once, you have 1024 possible ways for that test to come out, assuming Pass/Fail is completely binary, as opposed to real testing, which is more like Pass/Fail/WTF. > What about having little code to throw away and rewrite if you don’t like it, leasing to a faster refactoring cycle time and a better expression of your intent after s set time? Throwing code away doesn't hurt my feelings. > Or leading to readability simply being less important because the cost of rewriting 50 lines from scratch is so much lower than rewriting 10,000 lines from scratch? I can't rewrite what I can't read. I would struggle to rewrite code I struggle to read. > Or if you’re writing documentation and there’s an order of magnitude less code to write about? Writing documentation based on LoC count is deranged. > The whole style isn’t just “golf the character count”, but “collapse down the size of everything so one human attention covers a lot more of it, like zooming out to get a higher overview”. And we circle back around: Lisp macros allow me to zoom out like that by letting me factor out common patterns more easily, like collapsing all possible "assignment pattern" instances to a setf invocation. I don't see the guts of how assignment is done for that particular kind of data when I'm focused on the other bits of the codebase. It's out of focus for me then, and it collapses neatly into one little form. But, and here's the big sticking point for me, I can do all that without variable names which look like line noise.
- bakul 7y agoI use a slightly different DO macro. For example, DO(count(v)) v[i]=i; DO(3,4) a+=i*10+j; DO(3,4,5) a[i][k]+=b[i][j]*c[j][k]; Where i,j,k are first, second and third indices. So i in the last example takes values 0..2, for each i value j takes values 0..3 and for each j value k takes values 0..4.
- geocar 7y agoCool! I've often thought about the best way to do this, and your suggestion is compelling. I'm going to try it out.
- bakul 7y ago:-) The macrology is a bit grody and my DO implementation doesn't extend past 3 args.
- geocar 7y agoI'm interested to know what you think is "grody". This is what I came up with: #define DO(...) for(long long _a[]={__VA_ARGS__,1,1,1,1},i=0;i<*_a;++i) \ for(long long j=0;j<_a[1];++j)for(long long k=0;k<_a[2];++k) It doesn't seem bad to me, and it'd be pretty easy to extend or add asserts to catch when you introduce a fourth arg. gcc also appears smart enough to remove the unnecessary loads, so I'm going to keep playing with it.
- bakul 7y agoClever use of `__VA_ARGS__`! Does gcc remove `_a` as well? Well, may be it was just my implementation: #define mkmacro(func, ...) mkmacro_(func, VA_NUM_ARGS(__VA_ARGS__)) #define mkmacro_(func, nargs) mkmacro__(func, nargs) #define mkmacro__(func, nargs) func ## nargs #define DO(...) mkmacro(DO, __VA_ARGS__)(__VA_ARGS__) #define DO1(n) for(I i=0;i<(n); i++) #define DO2(m,n) DO1(m) for(I j=0;j<(n);j++) #define DO3(l,m,n) DO2(l,m) for(I k=0;k<(n);k++)
- 7y ago