Re:Bad programming ideas that only become apparent after years
by habitue on Sunday December 27, 2020 @12:59PM
(#25552834)
Re macros: I think this is entirely a cultural thing.
For example, in lisp, macros are used ubiquitously, and I think if anyone was going to criticize macros as a language feature it would be based on what they've seen in lisp (or C, but let's ignore that for the moment).
Meanwhile, in python, there are extensive metaprogramming facilities that could easily be used to make code very hard to understand (Even if you never use eval, you have decorators, metaclasses and descriptors etc).
I think the difference is cultural. Python has a norm of resorting to metaprogramming as a last resort, and largely in libraries and frameworks, not in application code. Certainly there's no compiler forcing people not to use all of the flexibility available in python at every turn. Even compared to a similar language like Ruby, python metaprogramming use is generally pretty restrained.
(My understanding of the implied context is that Walter Bright, the creator of D, is likely looking at macro usage in lisp, and inferring that macros are a mistake in a language like Rust. I know Walter is on here pretty often so if I'm guessing wrong here feel free to correct me)
Re:Bad programming ideas that only become apparent after years
by bsder on Sunday December 27, 2020 @09:04PM
(#25556052)
> Re macros: I think this is entirely a cultural thing.
I suspect there is also a generational divide.
Lisp is such an old language that I often wondered if it has so many macros because they didn't have the equivalent of "defun-inline". ie. That far too many usages of macros in the Lisps were for performance rather than for abstraction.
In modern languages, though, macros are really the only way to get at something like the AST of a language and act like the original developers of the language. I personally approve of this--the Go "Me, but not for thee" attitude of the language developers pisses me off.
However, given such power, usage of a macro should set off your "I'm using a macro. This language ecosystem is deficient somehow". And that should give you pause and you should ask "Am I really adding something to this language or am I just carrying over my habits from other languages?"
Finally, using a macro merely for "abstraction" should set off gigantic klaxon warning bells. A macro has to pass a really high bar if you could actually do the task with just functions and a little extra bit of keyboard typing.
Re:Bad programming ideas that only become apparent after years
by ashkankiani on Sunday December 27, 2020 @01:55PM
(#25553301)
Calling it cultural doesn't make sense to me, considering every difference you pointed out was based on the language's support for macros. C macros are a text generation hack from 40 years ago, lisp macros are a first class citizen, python metaprogramming is supported first class but hard to debug because of python's debugging tools. It's easy to see that the problem isn't "cultural," but the language's design and tooling.
Re:Bad programming ideas that only become apparent after years
by milesvp on Sunday December 27, 2020 @04:01PM
(#25554226)
> operator overloading for non-arithmetic purposes
I’m not sure it makes it a ‘good’ idea, but I recently needed to overload [] on an embedded system. The chip we used in a design didn’t have enough pins for both SPI and external memory. One of the memory address pins was used for both. So we wired up the memory skipping over the pin. This led to odd behavior that didn’t make sense until the original hardware engineer remembered he’d had to build it this way as a price compromise (the chip with enough pins would have probably been double the price). So I had to make sure that an adress translation happens on every access to DRAM, and overloading array access was a very obvious clean way to do this for any code that already did array access.
Re:Bad programming ideas that only become apparent after years
by majewsky on Sunday December 27, 2020 @04:41PM
(#25554507)
I think this is what Walter gets at with "only becomes apparent after years". Right now, you are aware that a[i] is not exactly (only practically) identical to *(a + i). The problem only arises when, years later, someone who reads the code does not realize that. Writing getoffset(a, i) instead of a[i] is uglier, but it will correctly prompt the reader to check out the definition (or documentation) for getoffset().
Re:Bad programming ideas that only become apparent after years
by milesvp on Monday December 28, 2020 @04:12AM
(#25557817)
Yeah, it's actually worse than that. Anyone trying to access DRAM on this hardware rev needs to be aware of the problem. Whether or not they use [] in that particular code they need to know that memory accesses will bite them. They also need to make sure that their data structures are byte aligned with the memory boundary, or they're going to have impossible to debug bugs. Especially since the debugger has no way to know that DRAM is wired funny, so you can't trust it's output.
There were really no clean ways to deal with this hardware compromise. Avoiding [] to Leave some bread crumbs around is maybe an ok solution. But there are bigger breadcrumbs around, like the malloc() implementation that is needed for this hardware.
Re:Bad programming ideas that only become apparent after years
by eyelidlessness on Sunday December 27, 2020 @03:11PM
(#25553863)
I don’t know. I’m personally partial to FP, but I tend to work in languages where it’s not the dominant paradigm, and where throwing exceptions is more idiomatic than say Either types. For those cases, checked exceptions are much nicer than having no error handling semantics in the type system. At least if you generally know what kinds of error cases are likely you can guard against them.
Re:Bad programming ideas that only become apparent after years
by choeger on Sunday December 27, 2020 @12:30PM
(#25552576)
The "macros" bit is obviously too vague, but of course even the best possible macros introduce barriers to reading the code, which is often very expensive.
I would generalize to the following: Everything that increases the time required to read the code is bad if it does not reduce the amount of code by a larger fraction.
So, refactoring code into a simple function that occurs once or twice is Ok, as long as that function can be found quickly in the same context (file, class, etc.). If the context is elsewhere, though, it is bad.
Similar for anything implicit (operator overloading, conversions, fancy type classes): If you need to switch context or even know about a completely different language feature or library to understand this code, that additional effort better saves a lot of code here.
Re:Bad programming ideas that only become apparent after years
by harperlee on Sunday December 27, 2020 @12:38PM
(#25552639)
And of course even the best possible functions introduce barriers to reading the code, which is often very expensive.
They are both abstractions that substitute an explicit operation with just a name; and thus both require that you expand your vocabulary when holding the program context in your head. Abstract at the wrong level, and you increase difficulty; abstract at the correct one, and you lower it.
Where I do think the main problem with macros is, is in debugging - because I know no macro system that maintains metadata on the written code to help explain the higher (macro) conceptual level once a stacktrace / condition / segfault / error arises.
Re:Bad programming ideas that only become apparent after years
by taeric on Sunday December 27, 2020 @12:44PM
(#25552699)
Amusingly, cweb does maintain line numbers. My mind was best blown the first time I saw a step debugger work on cweb source.
That said, with the proliferation of distributed systems that are commonly executing where you can't connect a debugger, I've found many aren't even aware of what they are missing. Jrebel, I recall, was very popular in some circles. Today, I'm not even sure most of my colleagues have ever used a debugger in a professional context.
Re:Bad programming ideas that only become apparent after years
by alpaca128 on Sunday December 27, 2020 @12:57PM
(#25552821)
In Rust println!() is a macro and it's just as readable as
stdout print commands in other languages, in fact it's simpler
than some.
Macros can be great if used to overcome a syntactical
limitation, in which case they can make the code more readable
and compact. If it introduces barriers to reading the code it's
not a good macro, and maybe unnecessary.
Re:Bad programming ideas that only become apparent after years
by dehrmann on Sunday December 27, 2020 @12:37PM
(#25552637)
At least in C, macros can change how the language works and have lots of gotcha semantics. I've written a decent amount of C, but also Java and Python, and I've never missed macros. You're better off with an inline function or not being clever.
Re:Bad programming ideas that only become apparent after years
by Gibbon1 on Sunday December 27, 2020 @04:39PM
(#25554491)
What I see as a bad idea is we created systems where the stack is a precious resource. For no actual good reason. You only have a few MB worth of stack. Why, because traditionally CPU's had one stack pointer.
We stick with this despite that stack allocation is vastly faster than heap.
Re:Bad programming ideas that only become apparent after years
by boxmonster on Sunday December 27, 2020 @03:39PM
(#25554057)
Walter Bright related his own tale about the problems macros can cause here: https://news.ycombinator.com/item?id=25423730 but that was with assembler, which is a whole nother kettle of fish
"The trouble was the author had used the macro language that came with the assembler to invent his own quirky, weird, undocumented and thoroughly impenetrable language. None of the programmers could figure it out. He was lamenting that he'd have to assign a programmer to recreating it from scratch, which would take months and cost a lot of money." (This was related on the passing of Eric Engstrom, who fixed it)
Re:Bad programming ideas that only become apparent after years
by jart on Sunday December 27, 2020 @09:01PM
(#25556038)
That's a good story. I ran into the same issue when I wrote Actually Portable Executable. Most operating systems and libc implementation have been "ported to death" in the sense that it's nearly impossible to determine the actual typing of interface structs and typedefs, due to a labyrinthine web of #ifdefs and macros. So most of the time, rather than reading the C source code, I'd just read the object disassembly and STABS listings. It's very disheartening that open source can suffer such tragedy of the commons that the source code is less useful than the binaries. Tyranny of the minority.
Re:Bad programming ideas that only become apparent after years
by fayten on Sunday December 27, 2020 @01:17PM
(#25552997)
I don't agree with this line of thinking. This implies that after a certain period of time, you will have the insight to know these things are bad. If you don't agree, then are you just a bad programmer? If I have a differing opinion, have I not programmed enough to come to the same conclusion? What about programming languages like Lisp, Scheme, Nim, and Haxe where Macros are their bread and butter?
Different programmers use different tools. If the end product is the desired result, then let people use what works best for them. I don't use dynamically typed languages; I avoid them like the plague, but that doesn't mean there isn't a ton of good work being done in Python.
Walter is a brilliant language developer and has a lot of firm opinions of programming semantics. I hope to see him expand upon this post and share why he thinks programmers need to be careful using these constructs.
Re:Bad programming ideas that only become apparent after years
by fayten on Sunday December 27, 2020 @02:10PM
(#25553422)
Nearly all code regardless of advanced features can run into severe maintenance issues when domain knowledge is lost. Solving problems should not start with gate keeping features, but promoting better documentation.
Re:Bad programming ideas that only become apparent after years
by im3w1l on Sunday December 27, 2020 @05:44PM
(#25554920)
I think it's fair to say that the recent Bouncy Castle security bug happened because Java lacks operator overloading. With overloaded [], an accidental use of indexOf would have been obvious.
So I think [] has a place for containers. Overloading * and -> for smart pointers also makes things look a lot nicer. I think the more advanced indexing modes of numpy (and by extension tensorflow) were a mistake though. Those create weird edge cases and would have been much better of as named methods.
Re:Bad programming ideas that only become apparent after years
by drewcoo on Sunday December 27, 2020 @06:04PM
(#25555023)
What makes programming ideas good and bad? What is the intent of the introduction of those ideas?
Without something more we just have an authority appealing to himself. And all of us commenting with no shared basis for our claims and no path to consensus.
Re:Bad programming ideas that only become apparent after years
by iphorde on Sunday December 27, 2020 @12:35PM
(#25552626)
That is because it is his opinion. Most people that complain about something, don't fully understand it. I have 35 years of experience, and see nothing wrong with them.
Re:Bad programming ideas that only become apparent after years
by rualca on Sunday December 27, 2020 @04:34PM
(#25554456)
> That is because it is his opinion. Most people that complain about something, don't fully understand it.
I'm convinced a person like Walter Bright knows a thing or two about software development in general and creating and implementing programming languages in particular.
Re:Bad programming ideas that only become apparent after years
by im3w1l on Sunday December 27, 2020 @05:37PM
(#25554873)
Picking an authority and taking their every word as gospel, that is suitable for a lay person who lacks time to do their own research, but as professionals we should aspire to do better than that. We should consider Walter Brights weighing in as one data point among many.
Re:Bad programming ideas that only become apparent after years
by rualca on Sunday December 27, 2020 @06:07PM
(#25555041)
> Picking an authority and taking their every word as gospel (...)
The man makes his living designing and implementing programming languages.
He expressed his opinion on the subject of designing and implementing languages.
Enough with this petty anti-intellectualism. If you have nothing of value to add to the discussion please remain silent. Your ignorance is not comparable to someone else's knowledge and experience. Expressing envy and pettiness regarding other people's knowledge, skill, and professional accomplishments does not pass off as a technical argument. It just sounds petty.
Re:Bad programming ideas that only become apparent after years
by mixedCase on Sunday December 27, 2020 @07:45PM
(#25555609)
His argument was non-existent, but your fallacious appeal to authority only takes down the conversation even further. Call him out, request an explanation, see if this person is truly speaking out of their arse or if he's got a point we're missing.
Re:Bad programming ideas that only become apparent after years
by im3w1l on Sunday December 27, 2020 @06:16PM
(#25555091)
With this comment I'm certain. Hacker news hasn't turned into reddit. It has sunk below. 2020 claims another scalp. Rip HN, I'm thankful for what has been and I will miss your glory days
Re:Bad programming ideas that only become apparent after years
by jart on Sunday December 27, 2020 @09:19PM
(#25556117)
The fact that he's a language designer means we should be even more skeptical than usual when he says things like c macros are bad. Macros are a big stick that lets devs redesign languages on the fly, and language designers want to be the ones in control of design.
Re:Bad programming ideas that only become apparent after years
by stephen82 on Sunday December 27, 2020 @01:12PM
(#25552950)
<sarcasm>For sure he does not understand macros. Who the hell is he? Was he the first who designed and implemented the first C++ compiler in C++ itself? Or has he designed and implemented D programming language? Really @WalterBright, how dare you express your feelings based on your decades of personal and professional experience?</sarcasm>
Re:Bad programming ideas that only become apparent after years
by turndown on Sunday December 27, 2020 @12:39PM
(#25552653)
1 is situational, there are good and there are bad macro systems, implicit variable declarations are terrible, but beyond forced typecasting on operators(which maybe be impossible to avoid) I don't think overloading operators for non-arithmetic types is so bad so long as you're in a language where the types are annotated/easily knowable. If redefining operators is fine in math, I think programmers can manage it too.
Re:Bad programming ideas that only become apparent after years
by jart on Sunday December 27, 2020 @09:35PM
(#25556185)
> there are good and there are bad macro systems
Everyone and their grandmother uses the C Preprocessor. However comparatively few people have heard about its cousin m4 which was invented by the same people. m4 never caught on because it isn't very pleasant to use. I'm surprised no one here has mentioned it, since its existence is living proof of just how successful and amazing the C preprocessor is. https://wolfram.schneider.org/bsd/7thEdManVol2/m4/m4.pdf
Re:Bad programming ideas that only become apparent after years
by vips7L on Sunday December 27, 2020 @04:06PM
(#25554258)
I personally prefer null and exceptions over Option types and Results. The former provides felixbility within OOP if you use a lot of interfaces. I haven't struggled with null pointers since I started programming a long time ago.
Re:Bad programming ideas that only become apparent after years
by rualca on Sunday December 27, 2020 @04:32PM
(#25554445)
> I personally prefer null and exceptions over Option types and Results.
Personal preferences and all, I feel the comparison between Result and exceptions is somewhere between misguided and miopic. The Result type and exceptions do not serve the same purpose. Exceptions are not intended to handle control flow, and the Result type is not intended to handle exceptional behavior. Moreover, they are not mutually exclusive.
To provide an example, a Result type would be returned by a database query, and it would return Ok if an element was found or return a Fail if either an element didn't existed or was not valid. Meanwhile an exception would be thrown if a memory allocation error happened somewhere.
Re:Bad programming ideas that only become apparent after years
by joshuamorton on Sunday December 27, 2020 @09:36PM
(#25556194)
> I mean, not finding a record in a database is not an error, nor is getting a response to a HTTP request with status code 3xx or a 404 or a 409.
But in some languages, exceptions would be used to handle these cases. Admittedly, those languages are usually higher level than C/C++ (but both Java and Python would probably find it common to handle a 3xx or a 404 or a missing row with an exception)
At a high level, I think the important thing is that funct() -> Result<T> and func() -> T that may throw/raise an exception are basically equivalent. Result may require slightly more explicitness at (at least) one call site, but ultimately both allow you to return a T, or report some non-T result, in a structured way. The only difference is that exceptions force you to handle the result explicitly (although that may just mean a single call to value! or VALUE_OR_DIE, or whatever the "get the T or segfault/panic" method is). In this way, I really do think checked exceptions are highly analogous to Result types.
Implementations may have different performance tradeoffs, but those aren't implicit in the choice of exception vs. result.
For example, in lisp, macros are used ubiquitously, and I think if anyone was going to criticize macros as a language feature it would be based on what they've seen in lisp (or C, but let's ignore that for the moment).
Meanwhile, in python, there are extensive metaprogramming facilities that could easily be used to make code very hard to understand (Even if you never use eval, you have decorators, metaclasses and descriptors etc).
I think the difference is cultural. Python has a norm of resorting to metaprogramming as a last resort, and largely in libraries and frameworks, not in application code. Certainly there's no compiler forcing people not to use all of the flexibility available in python at every turn. Even compared to a similar language like Ruby, python metaprogramming use is generally pretty restrained.
(My understanding of the implied context is that Walter Bright, the creator of D, is likely looking at macro usage in lisp, and inferring that macros are a mistake in a language like Rust. I know Walter is on here pretty often so if I'm guessing wrong here feel free to correct me)
I suspect there is also a generational divide.
Lisp is such an old language that I often wondered if it has so many macros because they didn't have the equivalent of "defun-inline". ie. That far too many usages of macros in the Lisps were for performance rather than for abstraction.
In modern languages, though, macros are really the only way to get at something like the AST of a language and act like the original developers of the language. I personally approve of this--the Go "Me, but not for thee" attitude of the language developers pisses me off.
However, given such power, usage of a macro should set off your "I'm using a macro. This language ecosystem is deficient somehow". And that should give you pause and you should ask "Am I really adding something to this language or am I just carrying over my habits from other languages?"
Finally, using a macro merely for "abstraction" should set off gigantic klaxon warning bells. A macro has to pass a really high bar if you could actually do the task with just functions and a little extra bit of keyboard typing.
I’m not sure it makes it a ‘good’ idea, but I recently needed to overload [] on an embedded system. The chip we used in a design didn’t have enough pins for both SPI and external memory. One of the memory address pins was used for both. So we wired up the memory skipping over the pin. This led to odd behavior that didn’t make sense until the original hardware engineer remembered he’d had to build it this way as a price compromise (the chip with enough pins would have probably been double the price). So I had to make sure that an adress translation happens on every access to DRAM, and overloading array access was a very obvious clean way to do this for any code that already did array access.
There were really no clean ways to deal with this hardware compromise. Avoiding [] to Leave some bread crumbs around is maybe an ok solution. But there are bigger breadcrumbs around, like the malloc() implementation that is needed for this hardware.
http://literatejava.com/exceptions/checked-exceptions-javas-...
I would generalize to the following: Everything that increases the time required to read the code is bad if it does not reduce the amount of code by a larger fraction.
So, refactoring code into a simple function that occurs once or twice is Ok, as long as that function can be found quickly in the same context (file, class, etc.). If the context is elsewhere, though, it is bad.
Similar for anything implicit (operator overloading, conversions, fancy type classes): If you need to switch context or even know about a completely different language feature or library to understand this code, that additional effort better saves a lot of code here.
They are both abstractions that substitute an explicit operation with just a name; and thus both require that you expand your vocabulary when holding the program context in your head. Abstract at the wrong level, and you increase difficulty; abstract at the correct one, and you lower it.
Where I do think the main problem with macros is, is in debugging - because I know no macro system that maintains metadata on the written code to help explain the higher (macro) conceptual level once a stacktrace / condition / segfault / error arises.
That said, with the proliferation of distributed systems that are commonly executing where you can't connect a debugger, I've found many aren't even aware of what they are missing. Jrebel, I recall, was very popular in some circles. Today, I'm not even sure most of my colleagues have ever used a debugger in a professional context.
Macros can be great if used to overcome a syntactical limitation, in which case they can make the code more readable and compact. If it introduces barriers to reading the code it's not a good macro, and maybe unnecessary.
1. Garbage collection + Forced reference counting. Why penalise all programs?
2. Coroutines and futures. Just use actors, please.
3. Visual Rapid development tools. Because the moment you need to do something interesting, the tools limit you.
But for most problems, these don’t impose a meaningful penalty and do remove a huge cognitive burden. Why penalize all programmers?
We stick with this despite that stack allocation is vastly faster than heap.
"The trouble was the author had used the macro language that came with the assembler to invent his own quirky, weird, undocumented and thoroughly impenetrable language. None of the programmers could figure it out. He was lamenting that he'd have to assign a programmer to recreating it from scratch, which would take months and cost a lot of money." (This was related on the passing of Eric Engstrom, who fixed it)
> Macros can be a bad programming idea, but at least they are a fun bad programming idea
Ain't that the truth.
Different programmers use different tools. If the end product is the desired result, then let people use what works best for them. I don't use dynamically typed languages; I avoid them like the plague, but that doesn't mean there isn't a ton of good work being done in Python.
Walter is a brilliant language developer and has a lot of firm opinions of programming semantics. I hope to see him expand upon this post and share why he thinks programmers need to be careful using these constructs.
1) original programmer moves on, someone else maintains/fixes/owns the code
2) scope / features / scale expands over time generally, so bad decisions for extension / expansion / scaling become prominent
But really the article is about 1.
https://www.bleepingcomputer.com/news/security/bouncy-castle...
So I think [] has a place for containers. Overloading * and -> for smart pointers also makes things look a lot nicer. I think the more advanced indexing modes of numpy (and by extension tensorflow) were a mistake though. Those create weird edge cases and would have been much better of as named methods.
Without something more we just have an authority appealing to himself. And all of us commenting with no shared basis for our claims and no path to consensus.
I'm convinced a person like Walter Bright knows a thing or two about software development in general and creating and implementing programming languages in particular.
https://en.wikipedia.org/wiki/Walter_Bright
None of us is as smart as all of us.
I think it's fair enough to do the former, even if i don't agree with them, and likely won't change my mind in this case.
The man makes his living designing and implementing programming languages.
He expressed his opinion on the subject of designing and implementing languages.
Enough with this petty anti-intellectualism. If you have nothing of value to add to the discussion please remain silent. Your ignorance is not comparable to someone else's knowledge and experience. Expressing envy and pettiness regarding other people's knowledge, skill, and professional accomplishments does not pass off as a technical argument. It just sounds petty.
Everyone and their grandmother uses the C Preprocessor. However comparatively few people have heard about its cousin m4 which was invented by the same people. m4 never caught on because it isn't very pleasant to use. I'm surprised no one here has mentioned it, since its existence is living proof of just how successful and amazing the C preprocessor is. https://wolfram.schneider.org/bsd/7thEdManVol2/m4/m4.pdf
https://hinchman-amanda.medium.com/null-pointer-references-t...
Personal preferences and all, I feel the comparison between Result and exceptions is somewhere between misguided and miopic. The Result type and exceptions do not serve the same purpose. Exceptions are not intended to handle control flow, and the Result type is not intended to handle exceptional behavior. Moreover, they are not mutually exclusive.
To provide an example, a Result type would be returned by a database query, and it would return Ok if an element was found or return a Fail if either an element didn't existed or was not valid. Meanwhile an exception would be thrown if a memory allocation error happened somewhere.
I mean, not finding a record in a database is not an error, nor is getting a response to a HTTP request with status code 3xx or a 404 or a 409.
But in some languages, exceptions would be used to handle these cases. Admittedly, those languages are usually higher level than C/C++ (but both Java and Python would probably find it common to handle a 3xx or a 404 or a missing row with an exception)
At a high level, I think the important thing is that funct() -> Result<T> and func() -> T that may throw/raise an exception are basically equivalent. Result may require slightly more explicitness at (at least) one call site, but ultimately both allow you to return a T, or report some non-T result, in a structured way. The only difference is that exceptions force you to handle the result explicitly (although that may just mean a single call to value! or VALUE_OR_DIE, or whatever the "get the T or segfault/panic" method is). In this way, I really do think checked exceptions are highly analogous to Result types.
Implementations may have different performance tradeoffs, but those aren't implicit in the choice of exception vs. result.