Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

Otto Skorzeny posted:

Maybe in Python circles

What circles is it acceptable? In C, if you feed something that wants a pointer a random integer or something stupid like that, it's your bug that the thing crashed. It's not going to hand you back a thing saying "this is a bad pointer".

Adbot
ADBOT LOVES YOU

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip

Suspicious Dish posted:

What circles is it acceptable? In C, if you feed something that wants a pointer a random integer or something stupid like that, it's your bug that the thing crashed. It's not going to hand you back a thing saying "this is a bad pointer".

Well, besides the fact that passing an integer where a function expects a pointer will give a compile error unless the consumer has turned on the language's "no you shut the gently caress up dad" switch and explicitly cast it, it is indeed common in modern C to check for the validity and sanity of arguments rather than propagating an error. For instance, if I pass an address to a function that writes to FRAM that is out of bounds, I expect it to check the address for validity (and maybe alignment) and return an error code indicating the address was bad rather than to attempt the write and return an error code that the write failed.

HappyHippo
Nov 19, 2003
Do you have an Air Miles Card?

Otto Skorzeny posted:

Well, besides the fact that passing an integer where a function expects a pointer will give a compile error unless the consumer has turned on the language's "no you shut the gently caress up dad" switch and explicitly cast it, it is indeed common in modern C to check for the validity and sanity of arguments rather than propagating an error. For instance, if I pass an address to a function that writes to FRAM that is out of bounds, I expect it to check the address for validity (and maybe alignment) and return an error code indicating the address was bad rather than to attempt the write and return an error code that the write failed.

There's a difference between checking that the argument is valid and that it is of the right type. Passing an out of bounds address could reasonably happen and that should be checked. You're still passing the right type. By in a dynamic language it's also possible to pass something that's just the wrong type. There's no point in checking that on the function side because if you aren't even passing the right type something has gone so wrong that there's usually no sensible recovery possible. Is the caller of the function going to add code to handle the "opps you supplied a string instead of an int" error case? If they even knew it was an error case they would have passed the correct thing in the first place. If on the other hand you silently ignore the error or return something nonsensical you're just allowing bugs to go undetected.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

Otto Skorzeny posted:

Well, besides the fact that passing an integer where a function expects a pointer will give a compile error unless the consumer has turned on the language's "no you shut the gently caress up dad" switch and explicitly cast it.

What cast?

nielsm
Jun 1, 2009



Otto Skorzeny posted:

Well, besides the fact that passing an integer where a function expects a pointer will give a compile error unless the consumer has turned on the language's "no you shut the gently caress up dad" switch and explicitly cast it, it is indeed common in modern C to check for the validity and sanity of arguments rather than propagating an error. For instance, if I pass an address to a function that writes to FRAM that is out of bounds, I expect it to check the address for validity (and maybe alignment) and return an error code indicating the address was bad rather than to attempt the write and return an error code that the write failed.

And if you pass it a FooMode constant rather than a combination of BarFlags values, what then? C's type system can't save you from that. It's a programmer error that you can't really catch in any way at all, it's just going to produce nonsense.

Did you know? Incorrectly written programs will produce wrong results!

And I would say there is a difference between writing library code for general consumption and writing internal helper functions. In the first case yes I would expect some amount of sanity checking, but never so much that it would seriously impact performance. In the latter case, I expect myself and my team to not gently caress up.
(Python, at least 2.7, produces a crazy error if you try to use Pickle on an object missing or misimpementing a magic method. That can happen if you're doing things with __getattr__ or __getattribute__, and you get no hint what is actually wrong, just a "tried to call NoneType" error pointing somewhere into pickle.py. Fun. But it's something I doubt really can be sanity-checked properly, it's been a while since I bumped into it.)

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip
You didn't pass an integer there, you passed a variable of type void*. I think your point is that C's type system can't catch everything, which is true, but this is a silly way to point it given it doesn't satisfy the original example you gave and since void* is a magic hole in the type system that is implicitly castable to any other pointer type.



HappyHippo posted:

B[ut] in a dynamic language it's also possible to pass something that's just the wrong type. There's no point in checking that on the function side because if you aren't even passing the right type something has gone so wrong that there's usually no sensible recovery possible.

There are degrees and gradations of wrongness, and depending on the purpose of the code you're writing it will make sense to be more exhaustive or less so when checking your inputs. Depending on the type system of the dynamic language you're using it may be easier or harder to do this sort of checking, eg. in Perl/Moose roles will (sometimes) make it harder to not check for certain types of correctness than to check, whereas in Python you may be blowing up duck typing for no benefit if you are overzealous.



nielsm posted:

And if you pass it a FooMode constant rather than a combination of BarFlags values, what then? C's type system can't save you from that. It's a programmer error that you can't really catch in any way at all, it's just going to produce nonsense.
C's type system is especially weak and can't catch much, and indeed even a very good type system can't catch everything. That doesn't make it pointless to try and catch anything.


nielsm posted:

Did you know? Incorrectly written programs will produce wrong results!

Thank you for this pointless non-sequitur.


nielsm posted:

And I would say there is a difference between writing library code for general consumption and writing internal helper functions. In the first case yes I would expect some amount of sanity checking, but never so much that it would seriously impact performance. In the latter case, I expect myself and my team to not gently caress up.
I agree with this sentiment that greater amounts of checking are sensible for library-ish code.

HappyHippo
Nov 19, 2003
Do you have an Air Miles Card?

Otto Skorzeny posted:

There are degrees and gradations of wrongness, and depending on the purpose of the code you're writing it will make sense to be more exhaustive or less so when checking your inputs. Depending on the type system of the dynamic language you're using it may be easier or harder to do this sort of checking, eg. in Perl/Moose roles will (sometimes) make it harder to not check for certain types of correctness than to check, whereas in Python you may be blowing up duck typing for no benefit if you are overzealous.

Well the context here was using isinstance in python to check that the argument type is correct.

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip
That was the context of the discussion that preceded this one, yes.

Sang-
Nov 2, 2007

code:
[$] <> clang segfault.c
segfault.c:6:5: warning: implicitly declaring library function 'strcpy' with type 'char *(char *, const char *)'
    strcpy (p, "butts\n");
    ^
segfault.c:6:5: note: please include the header <string.h> or explicitly provide a declaration for 'strcpy'
segfault.c:11:11: warning: incompatible integer to pointer conversion initializing 'void *' with an expression of type 'unsigned int' [-Wint-conversion]
    void *p = 0xDEADBEEF;
          ^   ~~~~~~~~~~
2 warnings generated.
Pretty sure it does give a warning!

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Please include the header <string.h>

Titan Coeus
Jul 30, 2007

check out my horn
Found this on a settings page for my router

JavaScript code:
if("" != "") {
    document.write("");
}
else {
    document.write("");
}

QuarkJets
Sep 8, 2008

Wheany posted:

Well good thing your example is made up.

Sort of. I'm loosely describing actual applications without describing their specifics.

This isn't really relevant anyway, there are plenty of examples where you'd want to check that an object has certain attributes rather than just throwing an exception every time that something unexpected gets passed. You can do this with isinstance or try/except blocks.

I mean duck typing isn't about assuming that an object has certain attributes, it just relates to using an object's attributes in determining semantics rather than using an object's inheritance. I can understand generally assuming that an object has specific attributes and letting the user sort out any problems, but there are specific cases where that is not what you want to do.

quote:

What exactly do you plan on doing with the wrong kind of input?

What if the wrong kind of input is wrong in a way you did not anticipate? Is it now okay to have wasted an afternoon of computing resources?

If it doesn't have the same attributes as dict (keys, etc), then I won't bother trying to iterate over and print out the keys/values in that dict. The computational results still get saved elsewhere (because those are created independently of the method that uses the dict) and everything else is good, but the code didn't throw any exceptions because I've decided that the method in question isn't as important as the method that calls it.

If the user doesn't pass a dict-like object then I won't try to iterate over it and print the values.

quote:

What if the wrong kind of input is wrong in a way you did not anticipate? Is it now okay to have wasted an afternoon of computing resources?

If it's an object with mapping attributes, I'll treat it as an object with mapping attributes. If it's not, then I won't do anything with it. Simple as that.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
So what if it doesn't behave as you expect, and throws an exception itself when you try to access it? Does that make it somehow okay to waste those six hours of computation?

When is using isinstance a better idea than just wrapping a try-except around the whole thing?

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe
Maybe I don't understand your field, but I hope that if you had a program you wanted to run that takes 6 hours when fed "real" data, you would test it out on a small case/with a small amount of dummy data first, to check that it works.

Jonnty
Aug 2, 2007

The enemy has become a flaming star!

QuarkJets posted:

Sort of. I'm loosely describing actual applications without describing their specifics.

This isn't really relevant anyway, there are plenty of examples where you'd want to check that an object has certain attributes rather than just throwing an exception every time that something unexpected gets passed. You can do this with isinstance or try/except blocks.

I mean duck typing isn't about assuming that an object has certain attributes, it just relates to using an object's attributes in determining semantics rather than using an object's inheritance. I can understand generally assuming that an object has specific attributes and letting the user sort out any problems, but there are specific cases where that is not what you want to do.


If it doesn't have the same attributes as dict (keys, etc), then I won't bother trying to iterate over and print out the keys/values in that dict. The computational results still get saved elsewhere (because those are created independently of the method that uses the dict) and everything else is good, but the code didn't throw any exceptions because I've decided that the method in question isn't as important as the method that calls it.

If the user doesn't pass a dict-like object then I won't try to iterate over it and print the values.


If it's an object with mapping attributes, I'll treat it as an object with mapping attributes. If it's not, then I won't do anything with it. Simple as that.

All this is pretty much fair enough, but the fact remains that you should always use try/except rather than isinstance.

baquerd
Jul 2, 2007

by FactsAreUseless
All I need in my 6 hours of computationally expensive code is "On Error Resume Next".

ExcessBLarg!
Sep 1, 2001

Jonnty posted:

All this is pretty much fair enough, but the fact remains that you should always use try/except rather than isinstance.
I don't do Python, but I imagine that "isinstance" is equivalent to Ruby's "instance_of?"/"kind_of?" methods. And yeah, there's three different ways I deal with objects that might look like the right type or not:
  • Assume the object implements an appropraite interface, blindly call it, let the caller deal with a runtime exception.
  • When returning an exception is really unexpected, wrap calls around begin/rescue (try/catch), log in the rescue/catch block, and log at level INFO or WARN depending on how unexpected the situation is. You are using log4* right? Right?
  • If the call can accept objects of different interfaces (usually with different method names) and I have to distinguish between them, use "respond_to?" method to see if the object implements the method name I expect to call.
The only time I have to use "isinstance" equivalents is when I have a method that accepts objects with different interfaces, that actually consist of the same method names with different arguments or some crap. That's pretty darn rare. And even in those cases said method is usually aliased to a longer name that's somewhat unique to the interface, or at least better distinguishes the interfaces to each other.

In the absolute worst case, it's somewhat idiomatic in Ruby to include a "to_type" method for objects that implement the interface for a particular type without inheriting from the type's canonical class. For example, you may implement a data structure with a hash-like interface, but not implement from class Hash. In that case though you'd still implement a "to_hash" method that actually converts it to Hash, usually with some unfortuate memory costs. In that case though, it's still prefereable to replace "instance_of(Hash)" with "respond_to?(:to_hash)", and just call the methods directly as if it were a Hash. But even that "nicer" version is still last resort.

QuarkJets
Sep 8, 2008

Hammerite posted:

Maybe I don't understand your field, but I hope that if you had a program you wanted to run that takes 6 hours when fed "real" data, you would test it out on a small case/with a small amount of dummy data first, to check that it works.

Of course, but you can't always predict user behavior

QuarkJets
Sep 8, 2008

Jabor posted:

So what if it doesn't behave as you expect, and throws an exception itself when you try to access it? Does that make it somehow okay to waste those six hours of computation?

When is using isinstance a better idea than just wrapping a try-except around the whole thing?

If the user crafts an object that looks like a dict but throws an exception when you access it like a dict, then it would be their own problem in my implementation. You are correct in that a try block would do this better for a case where a user tried to implement a mapping type but hosed it up, I hadn't thought of that

To your last question, they are functionally equivalent if you are using collections.Mapping, except in the example you described.

HappyHippo
Nov 19, 2003
Do you have an Air Miles Card?

QuarkJets posted:

If the user crafts an object that looks like a dict but throws an exception when you access it like a dict, then it would be their own problem in my implementation. You are correct in that a try block would do this better for a case where a user tried to implement a mapping type but hosed it up, I hadn't thought of that

To your last question, they are functionally equivalent if you are using collections.Mapping, except in the example you described.

Assuming we're still talking about that code snippet you posted on the last page, the problem with it is that you're effectively hiding errors by returning false instead of throwing an exception. Basically the code is intended to tell you if the dictionary contains some element. By returning false if the argument isn't a dictionary you're effectively hiding bugs, and in a really subtle way since false is a common and expected return value from such a function. In static typing the compiler reports a type error at compile time. With dynamic typing you don't have that luxury so you have to make sure that it throws an error at run time. The best place to do this is right when it happens, as this makes debugging as easy as possible. Crashes caused by passing the wrong argument type are very easy bugs to fix. By returning false you're effectively delaying the error so that it will show up at some later time in the program. Then the person debugging has to retrace the steps to find out what went wrong until they eventually find that they called your function with the wrong arguments. That's if they even found the bug in the first place.

It reminds me of a criticism made of PHP in that "fractal of bad design" rant: given a choice between throwing an error and doing something nonsensical, PHP almost always chooses the nonsensical thing.

QuarkJets
Sep 8, 2008

HappyHippo posted:

Assuming we're still talking about that code snippet you posted on the last page, the problem with it is that you're effectively hiding errors by returning false instead of throwing an exception. Basically the code is intended to tell you if the dictionary contains some element. By returning false if the argument isn't a dictionary you're effectively hiding bugs, and in a really subtle way since false is a common and expected return value from such a function. In static typing the compiler reports a type error at compile time. With dynamic typing you don't have that luxury so you have to make sure that it throws an error at run time. The best place to do this is right when it happens, as this makes debugging as easy as possible. Crashes caused by passing the wrong argument type are very easy bugs to fix. By returning false you're effectively delaying the error so that it will show up at some later time in the program. Then the person debugging has to retrace the steps to find out what went wrong until they eventually find that they called your function with the wrong arguments. That's if they even found the bug in the first place.

It reminds me of a criticism made of PHP in that "fractal of bad design" rant: given a choice between throwing an error and doing something nonsensical, PHP almost always chooses the nonsensical thing.

Yes, I am doing that by design; instead of throwing an exception, I am raising a warning and proceeding because the submodule in question is really inconsequential in the grand scheme of things. I left out the print statements in the example

Sometimes it's useful to give the user some leeway and print warnings instead of making GBS threads in the user's lap at the first sign of a discrepancy.

QuarkJets fucked around with this message at 23:41 on Apr 22, 2013

HappyHippo
Nov 19, 2003
Do you have an Air Miles Card?

QuarkJets posted:

Yes, I am doing that by design; instead of throwing an exception, I am raising a warning and proceeding because the submodule in question is really inconsequential in the grand scheme of things. I left out the print statements in the example

Sometimes it's useful to give the user some leeway and print warnings instead of making GBS threads in the user's lap at the first sign of a discrepancy.

Ok at least you're printing warnings. I still think it would be better to leave that decision to the user of the function rather than making it for them. If they don't care about errors they can wrap that code section in a try/catch (or whatever the python equivalent is) themselves and log the errors. As an added benefit your functions will be smaller without the unnecessary type checking overhead.

HappyHippo fucked around with this message at 23:59 on Apr 22, 2013

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

QuarkJets posted:

Yes, I am doing that by design; instead of throwing an exception, I am raising a warning and proceeding because the submodule in question is really inconsequential in the grand scheme of things. I left out the print statements in the example

Sometimes it's useful to give the user some leeway and print warnings instead of making GBS threads in the user's lap at the first sign of a discrepancy.

Do your automated tests ensure that everything is OK though?

evensevenone
May 12, 2001
Glass is a solid.
The way to give leeway is to catch the exception and then do something intelligent based on what happened. That way you can take advantage of the whole hierarchy of exceptions.

ExcessBLarg!
Sep 1, 2001
Honestly the whole premise is quite strange to me. I regularly deal with long-running computations that take a day or two to finish one "cycle" of.

1. Six hours isn't really that long. If the cycles are crazy expensive or crazy unobtainable (supercomputer) then sure, but in those cases you make sure your poo poo works well in advance of launchin on those platforms. If something fucks up after six hours on a riff-raff machine, whatever, restart, go to bed.

2. I have difficulty coming up with a scenario where a user, when performing a limited-data test would provide the right kind of dict-like object, but when perfoming a full-data run would not. True, user behavior can't always be predicted, but generally users don't do crazy batshit stuff either, and if they do, it's certainly on them.

POKEMAN SAM
Jul 8, 2004
I came here to check out the latest in PHPLOLZ not to listen to a bunch of nerds spergin' out over terrible programming paradigms endlessly.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
You might want to try the plang thread in YOSPOS for that, then. Sorry to bother!

QuarkJets
Sep 8, 2008

Suspicious Dish posted:

Do your automated tests ensure that everything is OK though?

It's literally just printing the contents of a dictionary to the terminal as a convenience, and the dictionary has no influence on any other part of the code, so everything is definitely okay.

ExcessBLarg! posted:

Honestly the whole premise is quite strange to me. I regularly deal with long-running computations that take a day or two to finish one "cycle" of.

1. Six hours isn't really that long. If the cycles are crazy expensive or crazy unobtainable (supercomputer) then sure, but in those cases you make sure your poo poo works well in advance of launchin on those platforms. If something fucks up after six hours on a riff-raff machine, whatever, restart, go to bed.

2. I have difficulty coming up with a scenario where a user, when performing a limited-data test would provide the right kind of dict-like object, but when perfoming a full-data run would not. True, user behavior can't always be predicted, but generally users don't do crazy batshit stuff either, and if they do, it's certainly on them.

What I meant by my comment is that I can't predict whether a user will do the smart thing and perform a limited-data test before performing a full run. I just want to protect bad people from doing bad things to themselves :(

Back when I was doing grid computing at CERN and was still very new to Python, I used try/excepts all over the place. Sometimes this would allow me to extract good results despite some simple bone-headed mistake that I or someone else had made and that didn't present itself until the code had finished running on the grid. When your jobs might be queued for half a day before they even start running, limited tests and try/except blocks together help to save a lot of time. Obviously these aren't always enough, but sometimes they do the trick, and boy does it feel good when you have data despite some piece of the code not working as expected (so perhaps plots of 90% of my quantities are available, but a function that calculates/plots another 10% are bad; that's no problem if I still have a ton of great plots to show people!)

QuarkJets fucked around with this message at 07:26 on Apr 23, 2013

qntm
Jun 17, 2009
Some people manage to write C in every language. This is a good one that I saw today.

code:
for ($iterator = 0; $iterator < @matches; $iterator++) {
  if ( $matches[$iterator] =~ /value\ \'(.*?)\' / ){           
    break;
  }

  # ...
}
Perl doesn't have the break keyword. This just throws a warning because no subroutine named break has been defined, and continues with the rest of the block.

Toady
Jan 12, 2009

Tetraptous posted:

Mercurial is mostly the same as git, especially if you include extensions, and is maybe a little easier to learn. I like it.

As for Mac package management systems, after playing with all if them, I really do think MacPorts is the most mature and Brew the least. I like that Fink and MacPorts dump their stuff into special directories that you can remove with rm. Neither can break your system unless you configure them in a really weird and non-default way! For the most part, Macports only breaks itself when Apple updates the OS/Xcode. I don't like how Brew throws stuff into /usr/. Other stuff defaults to the same place.

MacPorts also has a great staff of developers. All the times I've requested a version update or filed a bug report, they responded within half an hour and addressed it within days.

Homebrew turned me off a little because of its original homepage publicly bashing MacPorts and acting like using Ruby made it amazing. It also doesn't require a password to install software, which makes me superstitious and paranoid, perhaps wrongly.

ozymandOS
Jun 9, 2004

qntm posted:

Some people manage to write C in every language. This is a good one that I saw today.

code:
for ($iterator = 0; $iterator < @matches; $iterator++) {
  if ( $matches[$iterator] =~ /value\ \'(.*?)\' / ){           
    break;
  }

  # ...
}
Perl doesn't have the break keyword. This just throws a warning because no subroutine named break has been defined, and continues with the rest of the block.

The real horror is the lack of use strict.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
C++ code:
image_t *
img_load_from_filename (char *filename)
{
    image_t *ret = NULL;
    boolean success = FALSE;
    do {
        char *path;
        FILE *f;
        image_header_t img_header;

        path = path_join (DATADIR, filename);
        if (path == NULL)
            break;

        f = fopen (path, "r");
        if (f == NULL)
            break;

        if (!img_read_header (&img_header, f))
            break;

        ret = malloc (sizeof (image_t)) + 8 * img_header.data_size;
        if (ret == NULL)
            break;

        if (!img_read (ret, f))
            break;

        if (fclose (f) < 0)
            break;

        success = TRUE;
    } while (FALSE);

    if (!success && ret != NULL) {
        free (ret);
        ret = NULL;
    }
    return ret;
}

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Clearly you're complaining about GNU whitespace conventions.

That is a rather awesome mistake; I'm not sure I've seen it before. It takes talent to soldier on against that kind of misparenthesization.

If the clang static analyzer doesn't catch it, you should file a bug. :)

Look Around You
Jan 19, 2009

rjmccall posted:

Clearly you're complaining about GNU whitespace conventions.

That is a rather awesome mistake; I'm not sure I've seen it before. It takes talent to soldier on against that kind of misparenthesization.

If the clang static analyzer doesn't catch it, you should file a bug. :)

I had to read over that code like 5 times before I realized where the mistake was. I'm surprised it runs at all.

Opinion Haver
Apr 9, 2007

What am I looking for?

Sedro
Dec 31, 2008
code:
ret = malloc (sizeof (image_t)) + 8 * img_header.data_size;
Edit: but the coding horror is do ... while (false)

Sedro fucked around with this message at 07:42 on Apr 27, 2013

Opinion Haver
Apr 9, 2007

Oh! That is subtle, yeah.

qntm
Jun 17, 2009

BP posted:

The real horror is the lack of use strict.

Oh, use strict was there. It had been commented out.

nielsm
Jun 1, 2009



Sedro posted:

Edit: but the coding horror is do ... while (false)

What no. GOTO is evil, you know!


In lesser wtf's, yesterday I found several cases of the "depending on X, always X" pattern in our code:
code:
(X > 0) ? X : X
Only X is a longer expression. (It turns out that once, the "else" part actually was 0 so it was just a lazy change to fix something. Not sure what.)

Adbot
ADBOT LOVES YOU

Doctor w-rw-rw-
Jun 24, 2008

Sedro posted:

code:
ret = malloc (sizeof (image_t)) + 8 * img_header.data_size;
Edit: but the coding horror is do ... while (false)

You do realize that "do{ ... } while(false);" is, in other places, a practical and useful construct in C, right? It creates a block around which multiple expressions or statements are still treated as one so as to not disrupt braceless if's.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply