5 ms·
> And this is, in fact, a made-up example but the thing is, I was a C programmer for the past 5 years, and I was working with low-level code (bare metal actuall
by xmcqdpt2 3y ago
> And this is, in fact, a made-up example but the thing is, I was a C programmer for the past 5 years, and I was working with low-level code (bare metal actually). And I have never seen the use of explicit scoping of variables. [...] I find this a major problem when dealing with C because I always see about 10 uninitialized variables at the start of each function, where half of those are used only once. Somewhere. And thank god, if there are no global variables.
Sure, if you write C like it's 1995, it's not going to be very readable. You don't need to define variable at the beginning of a scope, and you can use {} to scope variables to tighter blocks. And functions can be small.
(Sometimes you need to keep variables for longer than you would like for cleanup reason, that's true.)
- ctrw 3y agoSo your solution to having too many () is to have just as many {}. I'm not complaining but...
- PeterisP 3y agoWell, no, the above solution is to have a {} if and only if explicit scoping is desired instead of having just as many {} as there would be (). Sometimes you need explicit scope for a bunch of things and the code would benefit from it. That doesn't justify having explicit scopes for everything all the time.
- zelphirkalt 3y agoIsn't is always safer to have variables scoped only to the relevant part of the code, that is supposed to make use of them? So basically it would result in almost the same number of parens.
- lex-lightning 3y agoThis isn’t always possible, even in lisp. Compare to Rust’s non-lexical lifetimes
- zelphirkalt 3y agoI don't see how it could ever be not possible. Maybe not always convenient, but impossible? How?
- lex-lightning 3y agoa = getInt(); b = getInt() + a; c = getInt(); d = b / c; puts(d); puts(c); puts(b); puts(a); Nothing in the middle of this code prevents using ‘a’ even though it isn’t relevant to ‘c’. And there’s no way to arrange it to change that.
- zelphirkalt 3y agoIf `c` does not depend on `a`, then the re-arrangement seems simple: Define `c` later.
- susam 3y ago> If `c` does not depend on `a`, then the re-arrangement seems simple: Define `c` later. How does that prevent 'a' from being in the scope where 'c' is defined? It is not clear to me what you mean by defining 'c' later. Later where? And how do we ensure that 'a' is not accessible there? I think lex-lightning's comment has a point. We need to define 'a' and we need to define 'c' and then we need to print 'c' before printing 'a', so although 'c' does not depend on 'a', we still need to keep 'a' in scope because we cannot print it before we print 'c'. Perhaps a convoluted solution to the problem posed in lex-lightning's comment would be something like this: #include <stdio.h> int getint() { return 42; } int main() { int a = getint(); int b = getint() + a; int c; { // Shadow 'a' here to make the outer 'a' inaccessible in this scope. int *a = NULL; (void) a; c = getint(); } int d = b / c; printf("%d\n", d); printf("%d\n", c); printf("%d\n", b); printf("%d\n", a); return 0; } Output: $ cc -std=c99 -Wall -Wextra -pedantic foo.c && ./a.out 2 42 84 42
- 3y ago
- lex-lightning 3y agoThe drawback of the microscopic function craze is you lose the ability to read a whole procedure from top to bottom. If some code is truly reused, break it out into a function with a good name, sure. But in my domain I have seen countless one-line functions used in one place each, and it’s frustrating having to jump around the code (and add to my mental context stack*) rather than just putting some curly braces and a comment. Functions aren’t primarily meant as a hygiene mechanism. I really like the curly brace scoping in Rust. I found my style partly by reading John Carmack and Casey Muratori’s coding philosophies and putting them to the test for myself. * For a natural language analogy, consider the difference between parenthetical remarks and asterisks. You have to remember your place in the text.
- jolt42 3y agoI define functions as often in let/letfn blocks than I do as separate functions, so they are local and in context. Makes it easy to read.
- lex-lightning 3y agoThis sounds like another option while maintaining agreement with the gist of what I meant. Those are good, though that’s where I start preferring smallness
- agentultra 3y agoIt's a personal preference based on how we mentally model problems. I cannot stand long procedural code. The mental gymnastics required to know what it does is too much. More than 5-6 variables in scope and I have no idea if it does what you say it does. It would take me some time to figure that out. If it is under test we can at least say it's not wrong some times. I much prefer breaking problems down to the level where I can reason in terms of sets, algebras, and that sort of thing. It's much easier for my brain to rely on properties and the ability to substitute terms in equations than it is to reconstruct a giant state machine and execute it in my head. Much more so when we add concurrency to the mix. At the end of the day though I don't think there's, "one true way."