RUST Discussion
-
It was meant to be bloody vague - my point isn't "you can use break or whatever in place of goto", but "there's always a better way to do something than goto". When making a list of features, it's easy to forget some particular one that you will then write a matching goto-using code where this feature would be perfect, and when I say that you can use this feature instead, you would be all blakeyranty about me not saying in my original post that this feature was allowed.
This is the bit where I smack you with a rolled up newspaper for being wilfully obtuse.
*SMACK*
The argument I was making was that, as sane control flow patterns are identified that previously required a
goto
to implement, they get rolled into languages as more structured constructs. But it's a big step to go from this dynamic process of discovery to declaring that it is safe to declaregoto
as being entirely obsolescent.A sign that things aren't really right is when you've got some sort of boolean involved that states whether a particular place in the code was reached. If you're doing that, you're encoding control flow in your data flow, and that is a code smell…
My argument is that it isn't just much smaller, but literally empty.
I still have that newspaper. ;-)
State machines are now being made using composition and hierarchical polymorphism.
I'm not convinced that that's a necessary improvement. A key desire of any control-flow innovation is that it should make crystal clear what is going on, not hide it behind another layer of syntax.Although TBH, parameterized breaks are clearer. Not all languages have then, however.
This is an area where C++ is not leading, as it is relatively difficult to create new syntactic constructs in that language. Other languages allow much more power to innovate (typically at a cost in terms of performance, which is definitely acceptable to some).I think Java's labelled loops are better than PHP's numeric-labelled
break
, if only because the latter opens up the possibility of computing how far to break back, which gives me cold shivers…
-
I think Java's labelled loops are better than PHP's numeric-labelled break, if only because the latter opens up the possibility of computing how far to break back, which gives me cold shivers…
+û
-
This is an area where C++ is not leading, as it is relatively difficult to create new syntactic constructs in that language.
Hmm, I suppose a macro around
goto
and/orlongjmp()
is the immediately obvious suggestion here... *evil grin*
-
What's the actual difference between
break label;
and
goto label;
? Just the restrictions on when it can be used? Why not just have a convention that goto can only be used in a loop?
-
No no no, the
goto
one is vastly worse to thebreak
one becausegoto
is evil, see?
-
Give me one example of when goto is a better choice than a loop, a conditional, break, continue, an inner function, a switch, or any other programming technique that can solve the problem leads to less readable code than goto.
I definitely feel that error handling in C is a case wheregoto
is the least-bad solution.the lambda will be inlined
While I'll agree thatgoto
is acting as a workaround for a labeled break in that case, I think your lambda suggestion is still significantly less readable. IMO that's the sort of crappy workaround you'd use in a language that had neither labeled breaks nor gotos.(I also prefer
goto
to numbered breaks, e.g. Onyx'sbreak 2
, but not to actual labeled breaks.)This is an area where C++ is not leading, as it is relatively difficult to create new syntactic constructs in that language. Other languages allow much more power to innovate...
... what other languages?! One of what I view of C++'s few redeeming features is that I think it's much better than almost any other language at that. Lisps have it beat, Ruby has it beat, and... basically nothing else I know. It's not great, but plenty of languages give you almost no ability.
-
I think Java's labelled loops are better than PHP's numeric-labelled break, if only because the latter opens up the possibility of computing how far to break back, which gives me cold shivers…
I feel this, possibly unneeded, urge to point out I was being sarcastic in my post.
-
basically nothing else I know.
You need to get out more.
Seriously, learn more programming languages. You'll become better able to see the limitations in your tools, and a generally better programmer overall, even if you then decide that you're going back to using C++ anyway.
-
Seriously, learn more programming languages.
I've used quite a few languages across a wide range of paradigms. (The one paradigm I'm really missing is a stack-based language like Forth.) Care to suggest any before accusing me of having limited experiences instead of just having a different opinions on a particular languages's... syntactic flexibility?(I guess I have a couple others I could add if you count language extensions; Template Haskell and Camlp4, though I haven't actually used either.)
-
Care to suggest any before accusing me of having limited experiences instead of just having a different opinions on a particular languages's... syntactic flexibility?
Hypertalk!
-
And because I'd probably get to this eventually, let's look at some examples of things that you can do in C++.
- Pre-C++11 C++ doesn't support lambdas? You can make a syntax for expression lambdas out of core-language features.
- Pre-C++11 C++ doesn't support variadic templates? That's OK, you can use the preprocessor to fake them to a specified limit.
- C++ doesn't have strong typedefs? That's OK, you can make them out of core language features wrapped in a STRONG_TYPEDEF(...) macro.
The syntax for creating those abstractions isn't great (and in some cases is pretty awful), but I think C++ makes it possible to an extent that not many other languages match.
-
You can also write C++ while stabbing knitting needles through your dick Aztec-style... which is probably more pleasant than doing any of those three bullet points.
-
Clearly I have too much free time.
extern "C" int printf(const char*,...); static int X=100,Y=100,Z=100; extern "C" { int dolots_goto(int q) { int result = 0; for(int i=0; i<X; i++) { for(int j=0;j<Y;j++) { for(int k=0;k<Z;k++) { result += (j-i)*(k-j); if(k>q-j) { goto skipped_rest_of_yz; } } skipped_rest_of_yz: ; } } return result; } int dolots_lambda(int q) { int result = 0; for(int i=0; i<X; i++) { [&] { for(int j=0;j<Y;j++) { for(int k=0;k<Z;k++) { result += (j-i)*(k-j); if(k>q-j) { return; } } } }(); } return result; } } int main() { int v; v = dolots_goto(30); printf("result = %i\n", v); v = dolots_lambda(30); printf("result = %i\n", v); }
The results are interesting:
C:\dev\local\loopgoto>g++ loopgoto.cpp -std=c++11 -O3 C:\dev\local\loopgoto>a result = -14383700 result = -2455200
The assembly output for the functions
dolots_goto()
anddolots_lambda()
are roughly the same length (you can thow a-s
on the end of theg++
command), but seeing as they don't actually do the same thing, it doesn't really seem productive to compare them further...
-
Pre-C++11 C++ doesn't support lambdas? You can make a syntax for expression lambdas out of core-language features.
You can, but (A) Boost, and (B) the resultant 'feature' is so awkward to use that you'd probably end up wishing you hadn't.
(And actually like C++. Well, parts of it, at least.) I agree with the general thrust of your comment but I dispute this bulletpoint!
-
Turns out gotos really are evil.
extern "C" int printf(const char*,...); static int X=100,Y=100,Z=100; extern "C" { int dolots_goto(int q) { int result = 0; for(int i=0; i<X; i++) { for(int j=0;j<Y;j++) { for(int k=0;k<Z;k++) { result += (j-i)*(k-j); if(k>q-j) { goto skipped_rest_of_yz; } } // skipped_rest_of_yz: ; } skipped_rest_of_yz: ; } return result; } int dolots_lambda(int q) { int result = 0; for(int i=0; i<X; i++) { [&] { for(int j=0;j<Y;j++) { for(int k=0;k<Z;k++) { result += (j-i)*(k-j); if(k>q-j) { return; } } } }(); } return result; } } int main() { int v; v = dolots_goto(30); printf("result = %i\n", v); v = dolots_lambda(30); printf("result = %i\n", v); }
-
Give me one example of when goto is a better choice than a loop, a conditional, break, continue, an inner function, a switch, or any other programming technique that can solve the problem leads to less readable code than goto.
Cleanup code on error in quite a few kernel sources, especially in drivers:
http://lxr.free-electrons.com/source/arch/s390/kernel/time.c#L1390
1390 static int __init etr_init_sysfs(void) 1391 { 1392 int rc; 1393 1394 rc = subsys_system_register(&etr_subsys, NULL); 1395 if (rc) 1396 goto out; 1397 rc = device_create_file(etr_subsys.dev_root, &dev_attr_stepping_port); 1398 if (rc) 1399 goto out_unreg_subsys; 1400 rc = device_create_file(etr_subsys.dev_root, &dev_attr_stepping_mode); 1401 if (rc) 1402 goto out_remove_stepping_port; 1403 rc = etr_register_port(&etr_port0_dev); 1404 if (rc) 1405 goto out_remove_stepping_mode; 1406 rc = etr_register_port(&etr_port1_dev); 1407 if (rc) 1408 goto out_remove_port0; 1409 return 0; 1410 1411 out_remove_port0: 1412 etr_unregister_port(&etr_port0_dev); 1413 out_remove_stepping_mode: 1414 device_remove_file(etr_subsys.dev_root, &dev_attr_stepping_mode); 1415 out_remove_stepping_port: 1416 device_remove_file(etr_subsys.dev_root, &dev_attr_stepping_port); 1417 out_unreg_subsys: 1418 bus_unregister(&etr_subsys); 1419 out: 1420 return rc; 1421 }
-
Needs more braces, otherwise you get the
goto error
bugif (failurecondition) goto error; if (failurecondition2) goto error; //if (failurecondition3) /*commented out, not applicable any more*/ goto error; ...
-
I think in a situation like that, I'd like to use macros to make the setting of the error condition, the checking of it, and the escaping to an error exit path be a consolidated whole:
static int __init etr_init_sysfs(void) { int rc; #define RESCUE(operation, rescueTarget) do{if((rc=(operation))!=0)goto rescueTarget;}while(0) RESCUE(subsys_system_register(&etr_subsys, NULL), out); RESCUE(device_create_file(etr_subsys.dev_root, &dev_attr_stepping_port), out_unreg_subsys); RESCUE(device_create_file(etr_subsys.dev_root, &dev_attr_stepping_mode), out_remove_stepping_port); RESCUE(etr_register_port(&etr_port0_dev), out_remove_stepping_mode); RESCUE(etr_register_port(&etr_port1_dev), out_remove_port0); return 0; out_remove_port0: etr_unregister_port(&etr_port0_dev); out_remove_stepping_mode: device_remove_file(etr_subsys.dev_root, &dev_attr_stepping_mode); out_remove_stepping_port: device_remove_file(etr_subsys.dev_root, &dev_attr_stepping_port); out_unreg_subsys: bus_unregister(&etr_subsys); out: return rc; }
Of course, I suspect you simply wouldn't write it like this in C++ in the first place — this feels like code that would map to something in a constructor with RAII dealing with the backout — but I'm not sure if that's a good thing or not in a kernel, where C++'s overheads are quite costly…
-
See, "parameterized breaks" are spelled goto in C++ :P
Except nothing prevents you togoto
from the inner loop to the initialization code half the function before, andbreak
can be used exclusively to go immediately after the closing bracket.Of course, I'd want to see the assembly language out for both versions of the function before a conceding that the lambda version is a valid replacement.
http://www.filedropper.com/testasm
Did testing with MinGW 4.8.1 with -std=c++11 and -S. The result is, at -Os the results are identical, at -O1, -O2 and -O3 some instructions are different between the two programs or in different order, with one or two more instuctions in lambda version. At -O0, lambda version is over 50% larger, but it doesn't count since I was speaking of optimizations.But it's a big step to go from this dynamic process of discovery to declaring that it is safe to declare goto as being entirely obsolescent.
Big steps are sometimes necessary.I'm not convinced that that's a necessary improvement. A key desire of any control-flow innovation is that it should make crystal clear what is going on, not hide it behind another layer of syntax.
The whole point of abstraction is to hide everything behind a layer of syntax - in order to make it clearer.current_state = blakeyrant
tells me much more thangoto blakeyrant
somewhere in the middle of one of several infinite loops (because that's the only way I can imagine goto being used to shift between states - I might be wrong though, and would love to see an example of doing it another way).What's the actual difference between
break label;
andgoto label;
?
That in case ofgoto
, the label can be anywhere.I definitely feel that error handling in C is a case where goto is the least-bad solution.
C is very old language. Saying thatgoto
is best thing you can do in C is like saying a black powder mortar is the best tool for assaulting enemy castle.While I'll agree that goto is acting as a workaround for a labeled break in that case, I think your lambda suggestion is still significantly less readable.
Every new syntax is unreadable. But if you get used to C++11 lambdas, it's obvious.The syntax for creating those abstractions isn't great (and in some cases is pretty awful), but I think C++ makes it possible to an extent that not many other languages match.
And then your codebase looks like shit. I cringe every time I have to write DECLARE_ENUM((MyNamespace)(MyEnum), (Foo)(Bar)).The assembly output for the functions dolots_goto() and dolots_lambda() are roughly the same length (you can thow a -s on the end of the g++ command), but seeing as they don't actually do the same thing, it doesn't really seem productive to compare them further...
Are you sure you don't get any signed integer overflow? Because technically, they are undefined behavior, and gcc -O3 loves trolling people over undefined behaviors.C++'s overheads (you've got failures, so you've got exceptions…)
Most C++ game developers disable exceptions in their compilers for this exact reason. Returning error codes is still a thing there.
-
The whole point of abstraction is to hide everything behind a layer of syntax - in order to make it clearer. current_state = blakeyrant tells me much more than goto blakeyrant somewhere in the middle of one of several infinite loops (because that's the only way I can imagine goto being used to shift between states - I might be wrong though, and would love to see an example of doing it another way).
But
next_state blakeyrant
may be more informative still in the overall context of the program.It's a feature of control-flow innovations that things that appear to be completely obvious and trivial after the fact are really very difficult to conceive of beforehand. They change how people think about problems. Examples include things like coroutines, which make doing interruptible synchronous state machines much easier, since they enable you to use control flow idioms to describe them instead of having to spread them over a bunch of functions (procedures, methods, etc).
I'm not very up to date on how they're done in C++ (there's boost::coroutine, but that looks horrific to me :) )
-
It's a feature of
control-flow innovationsprogramming languages that things that appear to be completely obvious and trivial after the fact are really very difficult to conceive of beforehand.
FTFYI'm not very up to date on how they're done in C++
They're not.
-
-
There are people who return from lookup functions via exceptions. There are people who mmap() memory to address 0. There are people who write GUI applications in Bash scripts. And there are people who use boost::coroutine and boost::spirit.
-
.... and all of those people can be politely shown the door and told they can expect their last paycheck in the mail.
-
-
I'm not sure if that's a good thing or not in a kernel, where C++'s overheads are quite costly…
Allegedly. I'm not entirely convinced myself and have a gut feeling that "it started in C, it stays in C" is prevailing.
Not that I have many fucks to give in that particular argument - having delved rather too deeply into the USB drivers for my liking in Linux some 7 years ago (hence knowing about this to begin with,) I have no desire to try and convince anyone of import of the benefits, or otherwise, of changing how they want to write their code and simply want to do as little as possible in there to get what I want doing, done.
Then GTFO ASAP.
-
The point where I realized you weren't talking about RUST
EDIT: While I still have write access to the OP, this is now the Rust Coding Help thread. Please post <del>teh codez</del> <ins>solutions</ins> to any of my Rust development scenarios <s>homework</s> below.
Or feel free to ask questions about Rust and one of our resident <del>experts</del> will get back toI guess you can code in RUST? Maybe it supports modding.
I tried to write a quick & dirty implementation of a Tree in Rust. I would imagine it's fairly entertaining to anyone who actually knows what they're doing:
[snip]
Assumption made, not looking at the code.
<small>Code was updated to use
if let
syntax...)</small>There's a function called
Tree::new()
which builds trees (calling intonew_help()
from time to time).You can build trees?
Once you've built a tree you can call
visit()
on it and visit each node in the order they were created.Visit is like a ElderScrolls COC call right?
Sorting (or in fact, anything useful at all) is not supported. Release early, release often!
If I wanted to go to town on it,
Ok, you built a town fast.
I'd probably spend a bit more time working on the
node!
macro to make building literal trees a bit less syntax heavy. Having to callTree::new()
and then use a special macro inside it is pretty dumb, but whatever. It's mildly less annoying thanTree::new(box Node(100, box Node(50, box Nil, box Nil), box Nil, box, box, box, box, pox, box, eggs and spam)
.Actually that maybe a sign that I'm probably doing too much boxing and unboxing,
Loot from boxes. Check!
and there's some reference-stealing shenanigans which I managed to hide by copying an object (I think) with
let q = *v; //weird
.Ok, I know you can't copy an object.WTF is RUST?Also I couldn't get closures to work properly for some reason, and all the online docs seem to be referring to a version of Rust that no longer exists, and that didn't help much either...
-
Not that I have many fucks to give in that particular argument - having delved rather too deeply into the USB drivers for my liking in Linux some 7 years ago (hence knowing about this to begin with,) I have no desire to try and convince anyone of import of the benefits, or otherwise, of changing how they want to write their code and simply want to do as little as possible in there to get what I want doing, done.
That reminds me of the crime against Linux I committed more than 20 years ago (my, how time flies!) in order to be able to run binaries from a mounted FAT16 filesystem. The problem? The files in FAT16 are not kilobyte-aligned on the disk, or at least not guaranteed to be so, and that made the Linux memory manager of the time really upset.
The hack I did to work around this — making all sectors in the filesystem except the first appear in virtual space to start 512 bytes later than they really did, together with some trickery in the sector calculations, because the hardware could load at 512 byte boundaries just fine — was never sent to anyone other than the person who commissioned me to do the work. It was a definite WTF, and clear to me that this was so even then. It worked quite well though; yes, there was a disk sector that appeared twice in the virtual map when my code decided to kick in, but it wasn't one that was normally read by anything.
Did I mention that I still truly hate FAT16? (FAT12 was just as bad, but had the advantage of being just about OK for the only thing it was ever actually used for: floppy disks.)
-
The point where I realized you weren't talking about RUST
At some point I tried googling something like "Rust Alpha Tutorial" and wound up on... that game site.
( are all these nekkid dudes in fields about and do they have to do with native development... )
-
native development... Surviving the native environment. Check!
<post not empty, stupid disco>
Again, is this RUST?
Hmmm..... programming is a survival game?
-
C is very old language. Saying that goto is best thing you can do in C is like saying a black powder mortar is the best tool for assaulting enemy castle.
And yet plenty of people still use it. You are the one who set the rules (saying there is no situation in which there's something better thangoto
), not me. You can't say "what I really meant was 'there's no situation in a modern language'". Well, I mean you could, but "my" counterexample still applies to what you originally said.I cringe every time I have to write DECLARE_ENUM((MyNamespace)(MyEnum), (Foo)(Bar)).
Like I said, the syntax isn't the greatest.... BUT, it at least gives you an option, more than most languages.
-
And yet plenty of people still use it. You are the one who set the rules (saying there is no situation in which there's something better than goto), not me. You can't say "what I really meant was 'there's no situation in a modern language'". Well, I mean you could, but "my" counterexample still applies to what you originally said.
Fix one loophole, make another... Okay, I admit that your counterexample is valid.
-
-
-
Needs more braces, otherwise you get the
goto error
bugif (failurecondition) goto error; if (failurecondition2) goto error; //if (failurecondition3) /*commented out, not applicable any more*/ goto error; ... ```</blockquote> And that is why the single line ifs are permabanned in my codebases. (commit hooks and build scripts do a syntax/style check). Shorthand notation is generally a bad idea or anything that works on assumptions in general (i.e. nobody addsany logic in between). I absolutely hate languages where the last expression result in the function is automatically the return value.
-
And that is why the single line ifs are permabanned in my codebases. (commit hooks and build scripts do a syntax/style check).
how does that help for this:
[code]
//if (failurecondition3) /commented out, not applicable any more/
{
goto error;
}
[/code]If the guy (or girl) was so full of fail that he couldn't properly comment out your example, what makes you think he (or she) could properly comment out ANY blocks of code.
-
how does that help for this:
//if (failurecondition3) /*commented out, not applicable any more*/ { goto error; } ```</blockquote> K&R bracing style for the win, again!
//if(fail) {
goto escape;
}
-
Do any C/C++ compilers have something like a
-Windent
that will warn if code violates, say, Python-ish indentation rules? Or any other tools for that?Edit: Nifty... looks like some LLVM folks are/were playing around with this idea. (Inspired by
goto fail
even.) No activity for 3/4 of a year though... But I also see references to it around places. Maybe it's in Clang? I don't have an install handy.
-
-Windent
That's the advantage of
{}
languages over Python—the compiler has the information it needs to double-check your indentation is consistent, and warn you about it if it isn't, rather than just doing something retarded instead.
-
That's the advantage of
{}
languages over Python—the compiler has the information it needs to double-check your indentation is consistent, and warn you about it if it isn't, rather than just doing something retarded instead.OTOH -- in Python, screwed-up block structure sticks out like a sore thumb to begin with, unlike
{}
languages, where it's possible for the indentation to totally lie to you about the block structure of the code.
-
I've written decent amounts of Python before, and honestly I have no problem with the lack of curly braces. Errors of the "wrong code block" type are pretty damned easy to detect in Python, frankly-- although I can see it becoming a problem if people get to "clever" with their syntax.
-
-
The most irritating problem that Python's lack of block delimiters caused me was the need to use
pass
occasionally to indicate that there's no code here:class BaseClass: def empty_base_class_function_for_overriding(): pass
-
-
how does that help for this:
[code]
//if (failurecondition3) /commented out, not applicable any more/
{
goto error;
}
[/code]If the guy (or girl) was so full of fail that he couldn't properly comment out your example, what makes you think he (or she) could properly comment out ANY blocks of code.
TBH, if someone fucks that one up, then well....special. The bracketless is easier to kludge.
Then again...we hired a senior programmer lady...who thought #ifdefs were runtime.....
so yea.
-
Random news: Rust alpha 2 comes out today. One of several dozen new features is that @tar's closure-returning function doesn't need explicit lifetime anymore. Also,
for &i in vec
instead offor i in vec.iter()
(if you omit the &, vec gets consumed, so be wary).
-
Random news: Rust alpha 2 comes out today. One of several dozen new features is that @tar's closure-returning function doesn't need explicit lifetime anymore.
Awesome. Can you return closures on the stack yet (that is, can function return type be an unboxed trait)?
-
Nope, not yet. Return type must be concrete, and closures are of local anonymous type that can't be named. But someone's working on it - it'll not be ready for 1.0, though.
-
who thought #ifdefs were runtime.....
ow
Back to your original commented out single line if conditional -
The main problem I saw with the kludge was that it wasn't properly indented, which makes it a lot harder to notice.I used to do the single line after an if method, but I always formatted it proper indentation and always made sure to put a blank line after the conditional statement so there is a noticeable difference.
eg.lines of code lines of code lines of code if (theBooleanThing) someFunctionThatDoesStuff(); morelinesofcode morelinesofcode morelinesofcode ``` Since a couple of years ago though, I stopped doing that and just started using braces 100% of the time, mostly for the types of reason in your posts above (and partly because if I always put the blank line after, what's the point in not using braces; it's not like I'm saving line space!)
-
When I do single-line ifs, I put everything on the same line. If I need more than one line, I use braces. It's foolproof.