On 24/06/11 21:46, George Neuner wrote:> On Thu, 23 Jun 2011 23:05:14 +0200, David Brown > <david.brown@removethis.hesbynett.no> wrote: > >> Copyrights are too long - you can blame the USA and their Mickey Mouse >> laws here. > > Actually you can blame Mickey Mouse. It was a dispute over Walt > Disney's copyrights that led to the current "life + 99 years" law > which automatically transfers the holder's rights to his/her estate > after death. >Yes, hence the popular name of the laws. Every time we get within sight of Disney (the company) losing the copyright on Mickey Mouse, Disney buys an update to the law extending copyright. Unless the USA changes its system of selling laws to rich corporations, or the rest of the world stops following them like poodles, then copyrights are now effectively unending.

Software Reuse In Embedded code
Started by ●June 15, 2011
Reply by ●June 25, 20112011-06-25
Reply by ●June 25, 20112011-06-25
Hi Arlet, On 6/25/2011 3:49 AM, Arlet Ottens wrote:> On 06/25/2011 10:39 AM, Don Y wrote: > >> The point here is that there are several places where "goto win" >> would have cleaned up the code. The do-while hack runs the >> risk of not being familiar to novices (and, also gives trouble >> if you want to "break break" -- requiring a flag and some >> kludge logic). And, the do-while cheats me out of three >> characters per line (because it introduces another indent level) > > I use goto whenever it results in clearer and more readable code. Using > "goto error" in a function that ends like this: > > error: > cleanup_stuff(); > return retval; > } > > is easy to understand.Exactly. Sometimes it's just clumsy/tedious to *not* resort to a goto. OTOH, too tolerant an attitude towards them tends to result in code that gets tangled and gnarly. If I find myself "needing" to resort to a goto, it forces me to rethink the way I have built the algorithm. OTOOH, note how often I "broke" MISRA rules in that code fragment. Rewriting it to consolidate all return's to a single point would have resulted in a real tanlged mess. Then, going back and removing the break's... etc.> The 'error' label makes it clear what the purpose > is, even without reading any further, and it helps to keep the mainline > code free of error handling. It may be possible to rewrite the code to > avoid the 'goto', but if that doesn't result in any tangible benefits, > why bother ?Simply because it is too easy to fall into the "routine" of resorting to goto to fix the structural errors in your code. IMO, it's a case where you *discourage* its use but never *forbid* it.> The extra indentation shouldn't be a problem, though. If you need more > than 3-4 levels of indentation, you should probably restructure the code > and/or use some extra functions anyway.It's *easy* to hit 4 levels of indent in the body of a non-trivial function. Wrapping clauses in function calls just muddies the waters for the sake of eliminating an indent level. E.g., gobble_leading_zeroes( char **ptr // IN/OUT references pointer to digit string ) { p = *ptr while (*p == 0) p++ *ptr = p } (or equivalent) I rely on the "shape" of my code on the "printed" page to convey a lot of information about it's structure. And, I *obsess* over whitespace (there's never enough!). E.g., the axiom that "a function should fit on a single page" just doesn't work for me -- unless you let me run the monitor in portrait orientation! :>>>> Similarly, I've seen a lot of code that is absolutely *infested* with >>> if/then/elses, where my background in hardware (Karnaugh maps, De >>> Morgan's theorem) has allowed me to simplify it to a few logical cases. >> >> <grin> I find I have to leave notes for folks explaining odd >> choices of conditionals. E.g., >> if (! ((*ptr != 'e') && (*ptr != 'E')) ) { >> though that would be a bad choice, here. > > I never worry about simplifying the logic, unless it helps readability.But that's the point! "if ((*ptr != 'e') && (*ptr != 'E'))" is the opposite of "if ((*ptr == 'e') || (*ptr == 'E'))" and, IMO, is easier to relate to than prefacing the latter with '!' I.e., "if it's not an 'e' and it's not an 'E', either, THEN..." instead of "if it's not: (an 'e' or an 'E') THEN..." Use these equalities to express things in easier terms with which to relate.
Reply by ●June 25, 20112011-06-25
On 06/25/2011 07:47 PM, Don Y wrote:> > Exactly. Sometimes it's just clumsy/tedious to *not* resort > to a goto. > > OTOH, too tolerant an attitude towards them tends to result > in code that gets tangled and gnarly. If I find myself > "needing" to resort to a goto, it forces me to rethink > the way I have built the algorithm.True, I very rarely have functions with more than 1 label in them, and if I use a goto it usually follows a particular idiom that easy to understand. There's never a good reason to get really tricky with gotos.> It's *easy* to hit 4 levels of indent in the body of a > non-trivial function. Wrapping clauses in function calls > just muddies the waters for the sake of eliminating an > indent level. E.g., > > gobble_leading_zeroes( > char **ptr // IN/OUT references pointer to digit string > ) > { > p = *ptr > while (*p == 0) > p++ > > *ptr = p > } > > (or equivalent)Why does a function like that muddy the waters ? One glance at the function explains how it works, and one glance at the caller explains what the purpose is. The function name provides free documentation. Although in this case, it probably doesn't help much, because the function is so simple, and the caller probably puts it in a bunch of easy to understand straight line code. With a slightly more complex function, it makes a lot of sense.> E.g., the axiom that "a function should fit on a single page" > just doesn't work for me -- unless you let me run the monitor > in portrait orientation! :>It nearly always works for me, unless the code is really straightforward, like a big case statement with simple cases.
Reply by ●June 25, 20112011-06-25
On 25/06/2011 11:49, Arlet Ottens wrote:> I use goto whenever it results in clearer and more readable code. Using > "goto error" in a function that ends like this: > > error: > cleanup_stuff(); > return retval; > } > > is easy to understand. The 'error' label makes it clear what the purpose > is, even without reading any further, and it helps to keep the mainline > code free of error handling. It may be possible to rewrite the code to > avoid the 'goto', but if that doesn't result in any tangible benefits, > why bother ?Aaaaiiieeee!! Steve -- http://www.fivetrees.com
Reply by ●June 25, 20112011-06-25
On 6/25/2011 5:06 PM, Steve at fivetrees wrote:> On 25/06/2011 11:49, Arlet Ottens wrote: >> I use goto whenever it results in clearer and more readable code. Using >> "goto error" in a function that ends like this: >> >> error: >> cleanup_stuff(); >> return retval; >> } >> >> is easy to understand. The 'error' label makes it clear what the purpose >> is, even without reading any further, and it helps to keep the mainline >> code free of error handling. It may be possible to rewrite the code to >> avoid the 'goto', but if that doesn't result in any tangible benefits, >> why bother ? > > Aaaaiiieeee!!I think you've bought all the vowels, Steve... would you like Vanna to try a *consonant*?
Reply by ●June 25, 20112011-06-25
Hi Arlet, On 6/25/2011 12:43 PM, Arlet Ottens wrote:>> It's *easy* to hit 4 levels of indent in the body of a >> non-trivial function. Wrapping clauses in function calls >> just muddies the waters for the sake of eliminating an >> indent level. E.g., >> >> gobble_leading_zeroes( >> char **ptr // IN/OUT references pointer to digit string >> ) >> { >> p = *ptr >> while (*p == 0) >> p++ >> >> *ptr = p >> } >> >> (or equivalent) > > Why does a function like that muddy the waters ? One glance at the > function explains how it works, and one glance at the caller explains > what the purpose is. The function name provides free documentation.It doesn't add much *value* for what it does. I.e., it just cuts out one level of indent from appearing in its place (I was referencing the code sample I posted up-thread) [the actual code is an eyesore because it uses up so much space on the page. But, trying to wrap portions of it in functions just kicks the can to other pages -- the code itself is so trivial that it doesn't "need" abstraction]> Although in this case, it probably doesn't help much, because the > function is so simple, and the caller probably puts it in a bunch of > easy to understand straight line code. With a slightly more complex > function, it makes a lot of sense. > >> E.g., the axiom that "a function should fit on a single page" >> just doesn't work for me -- unless you let me run the monitor >> in portrait orientation! :> > > It nearly always works for me, unless the code is really > straightforward, like a big case statement with simple cases.As I said, I like whitespace. So, lots of blank lines between stanzas. And, I like inserting "comment blocks" instead of tagging them on the ends of individual lines of code -- this quickly makes a function "longer".
Reply by ●June 26, 20112011-06-26
On 06/26/2011 02:58 AM, Don Y wrote:> Hi Arlet, > > On 6/25/2011 12:43 PM, Arlet Ottens wrote: > >>> It's *easy* to hit 4 levels of indent in the body of a >>> non-trivial function. Wrapping clauses in function calls >>> just muddies the waters for the sake of eliminating an >>> indent level. E.g., >>> >>> gobble_leading_zeroes( >>> char **ptr // IN/OUT references pointer to digit string >>> ) >>> { >>> p = *ptr >>> while (*p == 0) >>> p++ >>> >>> *ptr = p >>> } >>> >>> (or equivalent) >> >> Why does a function like that muddy the waters ? One glance at the >> function explains how it works, and one glance at the caller explains >> what the purpose is. The function name provides free documentation. > > It doesn't add much *value* for what it does. I.e., it just > cuts out one level of indent from appearing in its place > (I was referencing the code sample I posted up-thread) > > [the actual code is an eyesore because it uses up so much space > on the page. But, trying to wrap portions of it in functions > just kicks the can to other pages -- the code itself is so > trivial that it doesn't "need" abstraction] >I agree that in this case it doesn't make much sense to put this code in a function, but if you have a more complex function that needs 5 levels of indentation, using a function to bring that down to 3 levels usually does help to make it more readable. If you make the function 'static', and use it only once, the compiler will usually inline it, so it doesn't have any runtime cost.
Reply by ●June 27, 20112011-06-27
To expand my earlier vowel-heavy response: On 25/06/2011 11:49, Arlet Ottens wrote:> On 06/25/2011 10:39 AM, Don Y wrote: > >> The point here is that there are several places where "goto win" >> would have cleaned up the code. The do-while hack runs the >> risk of not being familiar to novices (and, also gives trouble >> if you want to "break break" -- requiring a flag and some >> kludge logic). And, the do-while cheats me out of three >> characters per line (because it introduces another indent level) > > I use goto whenever it results in clearer and more readable code. Using > "goto error" in a function that ends like this: > > error: > cleanup_stuff(); > return retval; > } > > is easy to understand. The 'error' label makes it clear what the purpose > is, even without reading any further, and it helps to keep the mainline > code free of error handling. It may be possible to rewrite the code to > avoid the 'goto', but if that doesn't result in any tangible benefits, > why bother ?There are any number of ways of avoiding this. One is to have an error flag; set it if you need to do cleanup (not great). Another is to return FALSE early if errors are encountered (see below; preferred). For me, using a goto is an admission of failure (to find a cleaner way), and I've not done this in 30+ years. There is *always* a better, cleaner, more comprehensible, and more robust way.> The extra indentation shouldn't be a problem, though. If you need more > than 3-4 levels of indentation, you should probably restructure the code > and/or use some extra functions anyway.I have a code-purity fascist at work ;). I love him dearly, as he's even more OCD than me. If I need a sanity check on something I'm doing, I run it past him. If he were to object to something I'm doing, it would make me think hard... but this hasn't happened yet. So... recently I ran something I do a lot past him. I had validation code that (simplified) looked like this: if ( ! first_bit_of_data_valid() ) return( FALSE ); if ( ! second_bit_of_data_valid() ) return( FALSE ); ... some processing... if ( ! processing_happy ) return( FALSE ); return( TRUE ); These "early returns" get objected to (by n00bs, mainly) on the basis that some see them as glorified gotos; I don't. I see them as structurally sound, since they all wind up in the same place (a return). Consider for a second the indentation levels of multiple tests for validity without early returns - every time you do a test, you indent one more time. (I have worse examples: imagine maintaining time of day, then date.) So anyway, my OCD colleague thoroughly approved ;).>>> Similarly, I've seen a lot of code that is absolutely *infested* with >>> if/then/elses, where my background in hardware (Karnaugh maps, De >>> Morgan's theorem) has allowed me to simplify it to a few logical cases. >> >> <grin> I find I have to leave notes for folks explaining odd >> choices of conditionals. E.g., >> if (! ((*ptr != 'e') && (*ptr != 'E')) ) { >> though that would be a bad choice, here. > > I never worry about simplifying the logic, unless it helps readability.Friend, I lost you right there. *Simplifying the logic can only help readability*. I suspect you're fairly new to this game (which I'm not) and have a few things yet to learn (as do we all). That's cool; don't be offended and try to keep an open mind about better ways. I've spent most of my career trying to find ways of keeping out of trouble (and being able to sleep nights) - that doesn't make my approach perfect (e.g. I avoid C++ at all costs, much to the scorn of my code-purity fascist colleague [I prefer good *design* over good *language*), but I do sleep nights [1]. Steve [1] Except tonight. Too bloody hot. Am sitting by the aircon. -- http://www.fivetrees.com
Reply by ●June 28, 20112011-06-28
Hi Steve, On 6/27/2011 5:33 PM, Steve at fivetrees wrote:> To expand my earlier vowel-heavy response:(sigh) I'd have rather watched Vanna twirl some consonants...>>> The point here is that there are several places where "goto win" >>> would have cleaned up the code. The do-while hack runs the >>> risk of not being familiar to novices (and, also gives trouble >>> if you want to "break break" -- requiring a flag and some >>> kludge logic). And, the do-while cheats me out of three >>> characters per line (because it introduces another indent level) >> >> I use goto whenever it results in clearer and more readable code. Using >> "goto error" in a function that ends like this: >> >> error: >> cleanup_stuff(); >> return retval; >> } >> >> is easy to understand. The 'error' label makes it clear what the purpose >> is, even without reading any further, and it helps to keep the mainline >> code free of error handling. It may be possible to rewrite the code to >> avoid the 'goto', but if that doesn't result in any tangible benefits, >> why bother ? > > There are any number of ways of avoiding this. One is to have an error > flag; set it if you need to do cleanup (not great).Booo! Then every conditional after that has to include "!error &&" (assuming you *don't* want to execute the code protected by the conditional if you've previously detected an error)> Another is to return > FALSE early if errors are encountered (see below; preferred).But, if error means some form of *recovery* is required, that means you have to wrap this portion of the code in a separate function -- so that the caller can examine that error return and unwind things, as appropriate. If doing that requires accessing something referenced *within* the called function (the one that "error returned"), then you have to make that data accessible to the calling function, etc.> For me, using a goto is an admission of failure (to find a cleaner way), > and I've not done this in 30+ years. There is *always* a better, > cleaner, more comprehensible, and more robust way.I don't think I would agree with that "unconditionally". I figure Ritchie, et al are pretty smart folks and didn't leave that feature in the language "casually". OTOH, when they created Limbo, the noticeably *removed* the "goto". OTOOH, in creating Limbo, the gave "continue" and "break" an optional argument -- an identifier indicating *which* enclosing "loop" is being referenced (in effect, where to "go to" as a result of the statement's execution). [this must give the MISRA folks fits! continue, break *and* goto all cohorting together!! :> ] I don't think anyone is questioning the *need* for "goto". But, rather, that ruling it out can make code clumsier (e.g., the Limbo break/continue fits my style of wrapping complex conditionals in do-while()'s and breaking, accordingly)>> The extra indentation shouldn't be a problem, though. If you need more >> than 3-4 levels of indentation, you should probably restructure the code >> and/or use some extra functions anyway. > > I have a code-purity fascist at work ;). I love him dearly, as he's even > more OCD than me. If I need a sanity check on something I'm doing, I run > it past him. If he were to object to something I'm doing, it would make > me think hard... but this hasn't happened yet. > > So... recently I ran something I do a lot past him. I had validation > code that (simplified) looked like this: > > if ( ! first_bit_of_data_valid() ) > return( FALSE ); > if ( ! second_bit_of_data_valid() ) > return( FALSE ); > ... some processing... > if ( ! processing_happy ) > return( FALSE ); > return( TRUE ); > > These "early returns" get objected to (by n00bs, mainly) on the basis > that some see them as glorified gotos; I don't. I see them as > structurally sound, since they all wind up in the same place (a return).This is equivalent to the example I posted. The problem comes in when what you really want is: if ( ! first_bit_of_data_valid() ) { cleanup_mess_from_first_bit(params1); return( FALSE ); } if ( ! second_bit_of_data_valid() ) { cleanup_mess_from_second_bit(params2); cleanup_mess_from_first_bit(params1); return( FALSE ); } etc. Sure, you can interpose another function to catch the "FALSE" return value... but, that function needs to be able to access all the stuff that the "cleanup" routines access -- potentially in the context of the "false-returning function". At some point, this just gets clumsy and forces you to go out of your way *just* to avoid a goto.> Consider for a second the indentation levels of multiple tests for > validity without early returns - every time you do a test, you indent > one more time. (I have worse examples: imagine maintaining time of day, > then date.)Exactly. This is the case with the arbitrary precision decimal arithmetic package I alluded to previously. The code isn't overly complex -- "tedious" is a better term (lots of care to be sure you don't have fence-post errors, etc.). Couple that with my preference for informative (i.e., *long*) identifiers and every level of indent starts to hurt. Especially as it forces same-line comments further and further out (making them shorter and less effective -- hence my preference for comment blocks)> So anyway, my OCD colleague thoroughly approved ;). > >>>> Similarly, I've seen a lot of code that is absolutely *infested* with >>>> if/then/elses, where my background in hardware (Karnaugh maps, De >>>> Morgan's theorem) has allowed me to simplify it to a few logical cases. >>> >>> <grin> I find I have to leave notes for folks explaining odd >>> choices of conditionals. E.g., >>> if (! ((*ptr != 'e') && (*ptr != 'E')) ) { >>> though that would be a bad choice, here. >> >> I never worry about simplifying the logic, unless it helps readability. > > Friend, I lost you right there. *Simplifying the logic can only help > readability*. I suspect you're fairly new to this game (which I'm not) > and have a few things yet to learn (as do we all). That's cool; don't be > offended and try to keep an open mind about better ways. I've spent most > of my career trying to find ways of keeping out of trouble (and being > able to sleep nights) - that doesn't make my approach perfect (e.g. I > avoid C++ at all costs, much to the scorn of my code-purity fascist > colleague [I prefer good *design* over good *language*), but I do sleep > nights [1].I will often rewrite conditionals to exploit things that I know to be true of the environment in which the code will operate. E.g., something that is more likely to affect a conditional one way or the other might get "promoted" to the front of the expression -- or, pulled into a separate expression "enclosing" the other expression (to emphasize that it is more significant to the algorithms performance). It's a minor efficiency hack but often can have rewards in loops, etc.> Steve > [1] Except tonight. Too bloody hot. Am sitting by the aircon.Pish! 30C? It's *40*C at 9P, here. High of 45C today. And tomorrow. (and I plan on being outdoors much of tomorrow :< ) Of course, unlike your 88%RH, we're sitting at something like *seven* %.
Reply by ●June 28, 20112011-06-28
On 06/28/2011 02:33 AM, Steve at fivetrees wrote:>> I use goto whenever it results in clearer and more readable code. Using >> "goto error" in a function that ends like this: >> >> error: >> cleanup_stuff(); >> return retval; >> } >> >> is easy to understand. The 'error' label makes it clear what the purpose >> is, even without reading any further, and it helps to keep the mainline >> code free of error handling. It may be possible to rewrite the code to >> avoid the 'goto', but if that doesn't result in any tangible benefits, >> why bother ? > > There are any number of ways of avoiding this. One is to have an error > flag; set it if you need to do cleanup (not great). Another is to return > FALSE early if errors are encountered (see below; preferred).Except that 'return FALSE' doesn't work in the case above where you also need to call 'cleanup_stuff()' unless you duplicate the cleanup code, which is even uglier than error flags.>> I never worry about simplifying the logic, unless it helps readability. > > Friend, I lost you right there. *Simplifying the logic can only help > readability*.Sometimes simplying the logic can help to increase readability, sometimes it doesn't. For the same reason, I sometimes write if( p ) and at other times I write: if( p != 0 ) Sometimes I write: if( a && b ), and sometimes I write: if( a ) if( b ) It all depends on the circumstances, and "how it reads". It's not necessary the case that the simplest logic is the easiest to read, although usually it helps, and in that case I obviously simplify the logic. > I suspect you're fairly new to this game (which I'm not) Yeah, I guess 25 years is fairly new.
