digitalmars.D - Is there any real reason to use "const"?
- rempas (27/27) Jan 24 2022 Rather than just tell the compiler to not allow me to modify a
- rikki cattermole (4/4) Jan 24 2022 If you are working with raw pointers, you need a way to express read
- rempas (24/28) Jan 24 2022 We would try to avoid working with pointers directly in read-only
- Dom DiSc (12/16) Jan 24 2022 You need const for functions that need to be able to take a
- Dennis (4/6) Jan 24 2022 I usually mark local variables `const` because it's shorter than
- rempas (14/25) Jan 24 2022 That's what I'm saying. If there were no "const" and it was up to
- Dennis (46/49) Jan 24 2022 There's this idea among some programmers that to prevent software
- =?UTF-8?Q?Ali_=c3=87ehreli?= (14/20) Jan 24 2022 Yeah, that thought disappears once one realizes that humans are
- rempas (13/26) Jan 24 2022 Yeah, really working towards accepting that but I'm getting
- H. S. Teoh (89/96) Jan 24 2022 I used to be a hardcore C programmer. So hardcore that I won an award in
- rempas (7/103) Jan 25 2022 I hear you very clearly! Thanks! No seriously... THANKS A LOT!!!
- H. S. Teoh (35/49) Jan 24 2022 Huh, for some reason I was under the impression that D does not allow
- Dennis (8/11) Jan 24 2022 D doesn't allow a single `;` loop body to prevent this mistake:
- Dennis (12/14) Jan 24 2022 That's why I use 'Egyptian braces' with a 'cuddled else':
- =?UTF-8?Q?Ali_=c3=87ehreli?= (16/29) Jan 24 2022 Luckily, humans are very adaptive and can be happy with the following
- H. S. Teoh (35/70) Jan 24 2022 I used to be a big fan of this style, in fact. But these days, I write
- Patrick Schluter (5/28) Jan 24 2022 Not really a problem in my experience (25 years of C + 5 years of
- rempas (11/13) Jan 25 2022 Makes sense when your code if finalized and (properly) checked
- vit (9/21) Jan 24 2022 `const` variable are necessary:
- bauss (7/17) Jan 25 2022 Sure thing but that's not realistic if you work professionally as
- rempas (6/12) Jan 25 2022 Yeah, the problem with me is that I almost thing about the most
- bauss (3/16) Jan 25 2022 Yeah but it's not the norm, especially not for big companies
- rempas (8/14) Jan 26 2022 When saying "we would try to avoid working with read-only memory
- rempas (3/18) Jan 26 2022 Yep! I answered two times in the same reply! You will only see
- Dennis (21/25) Jan 24 2022 You can? This compiles:
- rempas (5/30) Jan 24 2022 I thought I tried it out some months ago and it wasn't possible.
- Mark (14/41) Jan 24 2022 AFAIK, const is a contentious topic. You can find many previous
- Guillaume Piolat (5/6) Jan 24 2022 const has utility at interface boundaries. You don't want an API
- rempas (7/11) Jan 24 2022 I mean, I can understand and agree the cases where people will
- =?UTF-8?Q?Ali_=c3=87ehreli?= (13/17) Jan 24 2022 That's misleading. Making mistakes is an important part of learning. It
- Timon Gehr (3/12) Jan 24 2022 Actually I am very disappointed that passing rvalues by ref is now tied
- Patrick Schluter (5/16) Jan 24 2022 No, at API level it is also a documentation help. When a
- rempas (4/8) Jan 25 2022 We could also had a library reference documentation that explains
- Steven Schveighoffer (11/17) Jan 24 2022 If you want the compiler to help you prevent mistakes, yes. If you
- Walter Bright (4/7) Jan 24 2022 Immutable global data gets placed in read-only memory sections. Read-onl...
- rempas (6/10) Jan 24 2022 Read only memory? So in the same place where string literals are
- Walter Bright (3/7) Jan 24 2022 You can see this if you run an object file disassembler over the compile...
- H. S. Teoh (9/18) Jan 24 2022 It depends on OS support, obviously. But most commonly-used OSes ought
- rempas (4/7) Jan 25 2022 That's actually really amazing and IMO, it is how it should be.
- Steven Schveighoffer (6/15) Jan 24 2022 Sure, but const isn't necessary for that. Const is a compiler construct
- Walter Bright (2/7) Jan 24 2022 Yeah, but it's undefined behavior if you write to them.
- Walter Bright (6/14) Jan 24 2022 Also, immutable data can be merged together, reducing the memory footpri...
- H. S. Teoh (12/20) Jan 24 2022 Makes me curious: how feasible is it to have functions with identical
- jmh530 (25/35) Jan 24 2022 This reminds me of generics. In languages with generics, you can
- H. S. Teoh (56/86) Jan 24 2022 [...]
- Walter Bright (2/9) Jan 24 2022 It's quite feasible. I've considered adding that optimization many times...
- Paul Backus (20/22) Jan 24 2022 Cursory reseach suggests that the main obstacle to this is
- rempas (6/24) Jan 24 2022 Thanks for your time! My question is if you think that it will be
- Steven Schveighoffer (11/14) Jan 24 2022 Some newer languages are gravitating towards const by default.
- Walter Bright (7/10) Jan 24 2022 Not sure what you mean. This compiles:
- rempas (14/20) Jan 24 2022 Actually this compiles but what I thought that didn't was
- Steven Schveighoffer (12/39) Jan 24 2022 I know exactly what you were doing:
- rempas (5/17) Jan 25 2022 Yeah right, now I remember! I did it about 2 months ago in a
- forkit (12/14) Jan 24 2022 Well, if const were default, you could ask yourself, is there any
Rather than just tell the compiler to not allow me to modify a variable (like I don't know what I'm doing with my program), are there any reason to use "const" variables? Other than out of curiosity, I'm actually asking because I'm writing a transpiler and I want to know if I should support "const" (or the concept of immutability in general) or not. To me, "const" has a lot of burdens like: "should we use it all the time if we don't want to be sure that we won't modify a variable or only for critical ones?" "Then in this case, why not make "const" the default and use another word to allow a variable to be mutable (just like Rust and other languages)?" Also another problem is that I don't like the way "const" is treated in functions. For example, you cannot past "const" variables to functions that take non-const parameters even if we are using variables which are ALWAYS copied (which means than modifying them will not modify the original value). This is stupid because if I want to support "const" for a function, I need to make an extra instruction to copy the value to a new non-const variable that is created inside the function and make an extra instruction. Copying a value is not a slow operation but it can be for a big struct. And in any case, it is stupid and it pisses me off... So yeah, I would like to know as soon as possible if there are any real reasons to support something like that so I can implement it. What do you guys think?
Jan 24 2022
If you are working with raw pointers, you need a way to express read only memory. Because the CPU does have it, and if you tried to write to it, bye bye process.
Jan 24 2022
On Monday, 24 January 2022 at 10:13:02 UTC, rikki cattermole wrote:If you are working with raw pointers, you need a way to express read only memory. Because the CPU does have it, and if you tried to write to it, bye bye process.We would try to avoid working with pointers directly in read-only memory but in any case, I still think that the programmer should know what they are doing. The problem you described is why most language use a "string" type that is immutable (in case you point to a string literal) but they also have a way to allow you to modify a "string" type in case you have allocated memory. So it's always up to you. So that's how I see it and I can't see it going wrong. I mean, you will properly read documentation and learn the language right? Well that was sarcastic... no one properly reads documentation these days which is the reason why programmers do all these stuff bringing all the downsides along. I think we should not reward people that don't want to properly learn the language. At the same time I understand that a lot of languages don't have a proper tutorial (book, say it however you want) to teach people about the language. Some don't even have a full language/library reference so even advanced programmer that want to dig cannot learn the language. So they can't blame people for not knowing the language in the end but this is the language creators fault to begin with and I don't plan on doing that. I will make sure that people can have learning the language.
Jan 24 2022
On Monday, 24 January 2022 at 10:23:14 UTC, rempas wrote:The problem you described is why most language use a "string" type that is immutable (in case you point to a string literal) but they also have a way to allow you to modify a "string" type in case you have allocated memory. So it's always up to you.You need const for functions that need to be able to take a mutable or immutable variable as parameter. And as you don't know which it is, you have to either propagate the constness or make a mutable copy if you want to call a function (depending if the called function has its parameter declared const or not). So better to declare const wherever that is possible, to _avoid_ making useless copies. I would NEVER EVER declare a variable const. It's always either mutable or immutable. I would go as far as forbidding to declare variables const, it's just confusing and useless. const is only for parameters.
Jan 24 2022
On Monday, 24 January 2022 at 10:49:36 UTC, Dom DiSc wrote:I would NEVER EVER declare a variable const. It's always either mutable or immutable.I usually mark local variables `const` because it's shorter than `immutable`, and `immutable` doesn't buy me anything over `const` in those cases.
Jan 24 2022
On Monday, 24 January 2022 at 10:49:36 UTC, Dom DiSc wrote:You need const for functions that need to be able to take a mutable or immutable variable as parameter. And as you don't know which it is, you have to either propagate the constness or make a mutable copy if you want to call a function (depending if the called function has its parameter declared const or not). So better to declare const wherever that is possible, to _avoid_ making useless copies. I would NEVER EVER declare a variable const. It's always either mutable or immutable. I would go as far as forbidding to declare variables const, it's just confusing and useless. const is only for parameters.That's what I'm saying. If there were no "const" and it was up to the programmer to decide what to do, we wouldn't had to worry about all that. Is you string pointing to a string literal? Then don't use the "add" function to add more data to it! Or maybe have a member in the "string type" that will check if the string points to a string literal and in this case, allocate memory (for both the old and the new value), copy the old value and then add the new value! This is just so simple and easy for both the creators of the language and the users My point is if there is a true reason to implement "const" itself other than just protecting programmers that haven't read the documentation and are trying to modify a string literal? Any.. "practical" reason so to say.
Jan 24 2022
On Monday, 24 January 2022 at 11:23:38 UTC, rempas wrote:My point is if there is a true reason to implement "const" itself other than just protecting programmers that haven't read the documentation and are trying to modify a string literal?There's this idea among some programmers that to prevent software bugs, we just need more well-trained / competent people, "like myself". This opinion tends to wane over time as you start writing those bugs you thought you'd never write. I never understood the idea of people always including {} braces in if-statements and for-loops. The idea is to prevent this: ```D if (x) y(); z(); ``` What idiot would write something like that, `z()` is obviously not part of the if-statement anymore right? One day I had a single-line for-loop body, and to fix an error I quickly added an `import` statement above it, pushing the for-loop body outside the for-loop scope. Oops. Yesterday I wrote a bug like this: ```D void alphabeta(ref Field field, /*...*/) { // (...) Field fieldCopy = field; field.modify(); // < should be fieldCopy.modify() alphabeta(fieldCopy); // (...) } ``` I was debugging it and noticed that I might as well mark the `field` parameter `const` since it wasn't supposed to change. The next compile I immediately got an error pointing at the bug! Usually I mark variables/functions as strict as possible as early as possible, `const` / `scope` / `pure` / ` safe` etc. I don't know how many bugs I would have written when I wouldn't do that, but it's also comforting knowing that I don't have to worry about accidentally breaking these properties I rely on when I modify a part of the code days or weeks later. Because that's how it gets you: sure, you can do these checks yourself the first time you write a function, but will you do them again every time you make a modification in the future? The compiler can, you likely won't. That said, it can also be annoying marking all function parameters `const` appropriately to convince the compiler that you indeed don't modify a `const` variable. I've heard of C++ people applying a macro `#define const` to a remove all `const` from a const-correct codebase because they don't like dealing with it. If you don't think it's worth it, you can not mark parameters `const` if you also don't mark your variables `const`.
Jan 24 2022
On 1/24/22 04:31, Dennis wrote:I never understood the idea of people always including {} braces in if-statements and for-loops.[...]What idiot would write something like that,Yeah, that thought disappears once one realizes that humans are mistake-making machines. :)One day I had a single-line for-loop body, and to fix an error I quickly added an `import` statement above it, pushing the for-loop body outside the for-loop scope. Oops.I've done its counterpart just two days ago by commenting out one line (in somebody else's code): foreach(i; 0..2) // foo(); bar(); Oops! Now bar() is executed multiple times. I am saddened with this skipped-braces "optimization" because all that risk for just to skip writing two characters! Wow! Now... that's... interesting... :) Humans are really interesting... Ali
Jan 24 2022
On Monday, 24 January 2022 at 17:30:26 UTC, Ali Çehreli wrote:Yeah, that thought disappears once one realizes that humans are mistake-making machines. :)Yeah, really working towards accepting that but I'm getting closer and closer each day...I've done its counterpart just two days ago by commenting out one line (in somebody else's code): foreach(i; 0..2) // foo(); bar(); Oops! Now bar() is executed multiple times. I am saddened with this skipped-braces "optimization" because all that risk for just to skip writing two characters! Wow! Now... that's... interesting... :) Humans are really interesting... AliYeah, that's classic! Tbh, either force your users to use curly brackets or find a python like system that will not cause these types of errors. In my language this will be: ``` for i in 0..2: // foo() bar() ``` Ending up having an empty "for" statement and executing "bar()" only once.
Jan 24 2022
On Mon, Jan 24, 2022 at 05:38:45PM +0000, rempas via Digitalmars-d wrote:On Monday, 24 January 2022 at 17:30:26 UTC, Ali Çehreli wrote:I used to be a hardcore C programmer. So hardcore that I won an award in the IOCCC once (well OK, that's not something to be proud of :-D). Correctly answered a C question on an interview technical exam that even my interviewer got wrong. Was totally into the philosophy of "the programmer knows better, compiler please step aside and stop trying to restrict me". Believed my code was perfect, and could not possibly have any bugs because I mulled over every line and polished every character. Didn't believe in test suites because I hand-tested every function when I wrote it so there can't have been any bugs left. And besides, test suites are too cumbersome to use. Used to pride myself on my programs never crashing. (And the times they did I blamed on incidental factors, like I was too distracted because some idiot was WRONG on the internet, gosh the injustice!) Then I discovered D. And in particular, D's unittest blocks. Was very resistant at first (why would I need to test perfect code), but they were just so darned convenient (unlike unittest frameworks in other languages) they just keep staring at me with puppy eyes until I felt so ashamed for not using them. Then the unittests started catching bugs. COPIOUS bugs. All kinds of boundary cases, careless typos, logic flaws, etc., in my "perfect" code. And EVERY SINGLE TIME I modified a function, another unittest started failing on a previously-tested case (that I disregarded as having nothing to do with my change so not worthy of retesting). Then this awful realization started dawning on me... my code was NOT perfect. In fact, it was anything BUT perfect. My "perfect" logic that flowed from my "perfect" envisioning of the perfect algorithm was actually full of flaws, logic errors, boundary cases I hadn't thought of, typos, and just plain ole stupid mistakes. And worst of all, *I* was the one making these careless mistakes, practically EVERY SINGLE TIME I wrote any code. What I thought was perfect code was in fact riddled with hidden bugs in almost every line. Usually in lines that I'd written tens of thousands of times throughout my career, that I thought I could write them perfectly even in my dreams, I knew them so well. But it was precisely because of my confidence that these "trivial" lines of code were correct, that I neglected to scrutinize them, and bugs invariably crept in. Then I observed top C coders in my company make these very same mistakes, OVER AND OVER AGAIN. These were not inexperienced C greenhorns who didn't know what they were doing; these were top C hackers who have been at it for many decades. Yet they were repeating the same age-old mistakes over and over again. I began to realize that these were not merely newbie mistakes that would go away with experience and expertise. These mistakes keep getting made because HUMANS MAKE MISTAKES. And because C's philosophy is to trust the programmer, these mistakes slip into the code unchecked, causing one disaster after another. Buffer overflow here, security exploit there, careless typos that cause the customer's production server to blow up at a critical time. Memory leaks and file descriptor leaks that brought a top-of-the-line server to its knees after months of running "perfectly". And the time and money spent in finding and fixing these bugs were adding up to a huge mountain of technical debt. Today, my "trust the programmer" philosophy has been shattered. I *want* the compiler to tell me when I'm doing something that looks suspiciously like a mistake. I *want* the language to be safe by default, and I have to go out of my way to commit a mistake. I want the compiler to stop me from doing stupid things that I'd done a hundred times before but continue to do it BECAUSE HUMANS ARE FALLIBLE. Of course, I don't want to write in a straitjacket like Java makes you do -- there has to be an escape hatch for when I *do* know what I'm doing. But the *default* should be the compiler stopping me from doing stupid things. If I really meant to cast that pointer, I *want* to have to write a verbose, ugly-looking "cast(NewType*) ptr" instead of just having a void* implicitly convert to whatever pointer type I happen to have on hand -- writing out this verbose construct this forces me to stop and think twice about what I'm doing, and hopefully catch any wrong assumptions before it slips into the code. I *want* the compiler to tell me "hey, you said that data was const, and now you're trying to modify it!", which would cause me to remember "oh yeah, I *did* decide 2 months ago that this data should not be changed, and that other piece of code in this other module is relying on this -- why am I trying to modify it now?!". As Walter often says, programming by convention doesn't work. Decades of catastrophic failures in C code have more than proven this. Humans are fallible, and cannot be relied on for program correctness. We're good at certain things -- leaps of intuition and clever out-of-the-box solutions for hard problems. But for other things, like keeping bugs out of our code, we need help. We need things to be statically verifiable by the compiler to prove that our assumptions indeed hold (and that somebody -- namely ourselves 3 months after writing that code -- didn't violate this assumption and introduce a bug during a last-minute code change before the last release deadline). Weak sauce like C++'s const that can freely be cast away with no consequences anytime you feel like it, will not do. You *need* something strong like D's const to keep the human error in check. Something that the compiler can automatically check and provide real guarantees for. T -- Bare foot: (n.) A device for locating thumb tacks on the floor.Yeah, that thought disappears once one realizes that humans are mistake-making machines. :)Yeah, really working towards accepting that but I'm getting closer and closer each day...
Jan 24 2022
On Monday, 24 January 2022 at 18:48:48 UTC, H. S. Teoh wrote:I used to be a hardcore C programmer. So hardcore that I won an award in the IOCCC once (well OK, that's not something to be proud of :-D). Correctly answered a C question on an interview technical exam that even my interviewer got wrong. Was totally into the philosophy of "the programmer knows better, compiler please step aside and stop trying to restrict me". Believed my code was perfect, and could not possibly have any bugs because I mulled over every line and polished every character. Didn't believe in test suites because I hand-tested every function when I wrote it so there can't have been any bugs left. And besides, test suites are too cumbersome to use. Used to pride myself on my programs never crashing. (And the times they did I blamed on incidental factors, like I was too distracted because some idiot was WRONG on the internet, gosh the injustice!) Then I discovered D. And in particular, D's unittest blocks. Was very resistant at first (why would I need to test perfect code), but they were just so darned convenient (unlike unittest frameworks in other languages) they just keep staring at me with puppy eyes until I felt so ashamed for not using them. Then the unittests started catching bugs. COPIOUS bugs. All kinds of boundary cases, careless typos, logic flaws, etc., in my "perfect" code. And EVERY SINGLE TIME I modified a function, another unittest started failing on a previously-tested case (that I disregarded as having nothing to do with my change so not worthy of retesting). Then this awful realization started dawning on me... my code was NOT perfect. In fact, it was anything BUT perfect. My "perfect" logic that flowed from my "perfect" envisioning of the perfect algorithm was actually full of flaws, logic errors, boundary cases I hadn't thought of, typos, and just plain ole stupid mistakes. And worst of all, *I* was the one making these careless mistakes, practically EVERY SINGLE TIME I wrote any code. What I thought was perfect code was in fact riddled with hidden bugs in almost every line. Usually in lines that I'd written tens of thousands of times throughout my career, that I thought I could write them perfectly even in my dreams, I knew them so well. But it was precisely because of my confidence that these "trivial" lines of code were correct, that I neglected to scrutinize them, and bugs invariably crept in. Then I observed top C coders in my company make these very same mistakes, OVER AND OVER AGAIN. These were not inexperienced C greenhorns who didn't know what they were doing; these were top C hackers who have been at it for many decades. Yet they were repeating the same age-old mistakes over and over again. I began to realize that these were not merely newbie mistakes that would go away with experience and expertise. These mistakes keep getting made because HUMANS MAKE MISTAKES. And because C's philosophy is to trust the programmer, these mistakes slip into the code unchecked, causing one disaster after another. Buffer overflow here, security exploit there, careless typos that cause the customer's production server to blow up at a critical time. Memory leaks and file descriptor leaks that brought a top-of-the-line server to its knees after months of running "perfectly". And the time and money spent in finding and fixing these bugs were adding up to a huge mountain of technical debt. Today, my "trust the programmer" philosophy has been shattered. I *want* the compiler to tell me when I'm doing something that looks suspiciously like a mistake. I *want* the language to be safe by default, and I have to go out of my way to commit a mistake. I want the compiler to stop me from doing stupid things that I'd done a hundred times before but continue to do it BECAUSE HUMANS ARE FALLIBLE. Of course, I don't want to write in a straitjacket like Java makes you do -- there has to be an escape hatch for when I *do* know what I'm doing. But the *default* should be the compiler stopping me from doing stupid things. If I really meant to cast that pointer, I *want* to have to write a verbose, ugly-looking "cast(NewType*) ptr" instead of just having a void* implicitly convert to whatever pointer type I happen to have on hand -- writing out this verbose construct this forces me to stop and think twice about what I'm doing, and hopefully catch any wrong assumptions before it slips into the code. I *want* the compiler to tell me "hey, you said that data was const, and now you're trying to modify it!", which would cause me to remember "oh yeah, I *did* decide 2 months ago that this data should not be changed, and that other piece of code in this other module is relying on this -- why am I trying to modify it now?!". As Walter often says, programming by convention doesn't work. Decades of catastrophic failures in C code have more than proven this. Humans are fallible, and cannot be relied on for program correctness. We're good at certain things -- leaps of intuition and clever out-of-the-box solutions for hard problems. But for other things, like keeping bugs out of our code, we need help. We need things to be statically verifiable by the compiler to prove that our assumptions indeed hold (and that somebody -- namely ourselves 3 months after writing that code -- didn't violate this assumption and introduce a bug during a last-minute code change before the last release deadline). Weak sauce like C++'s const that can freely be cast away with no consequences anytime you feel like it, will not do. You *need* something strong like D's const to keep the human error in check. Something that the compiler can automatically check and provide real guarantees for. TI hear you very clearly! Thanks! No seriously... THANKS A LOT!!! I should constantly remind myself that a wise man always learns from mistakes that have made prior to him and always advance! Well I also found about "negation" overflow thanks to LDC2 so yeah, we must have the compiler protect us so "const" will be implemented! Thanks a lot for your time!
Jan 25 2022
On Mon, Jan 24, 2022 at 09:30:26AM -0800, Ali Çehreli via Digitalmars-d wrote:On 1/24/22 04:31, Dennis wrote:[...]Huh, for some reason I was under the impression that D does not allow un-braced blocks in a looping construct? Or maybe it's just self-imposed restriction that became subconscious, probably precisely because of bugs like these. If-statements are another trap waiting to happen... but so far I've found it very hard to resist the conciseness of: if (x == y) doSomething(); else if (y == z) doSomethingElse(); else doYetAnotherThing(); as opposed to the verbosity of: if (x == y) { doSomething(); } else if (y == z) { doSomethingElse(); } else { doYetAnotherThing(); } But in the former, it's too easy to e.g. add another line to the else block and forget the add the braces as well. For some reason I was under the impression that D didn't allow unbraced loop bodies because in the case of loops such errors could be a lot worse than in if-statements. T -- What do you get if you drop a piano down a mineshaft? A flat minor.One day I had a single-line for-loop body, and to fix an error I quickly added an `import` statement above it, pushing the for-loop body outside the for-loop scope. Oops.I've done its counterpart just two days ago by commenting out one line (in somebody else's code): foreach(i; 0..2) // foo(); bar(); Oops! Now bar() is executed multiple times.
Jan 24 2022
On Monday, 24 January 2022 at 17:55:39 UTC, H. S. Teoh wrote:For some reason I was under the impression that D didn't allow unbraced loop bodies because in the case of loops such errors could be a lot worse than in if-statements.D doesn't allow a single `;` loop body to prevent this mistake: ```D for (int i=0; i<l; i++); ``` You have to write {} for an empty body. It also doesn't allow dangling else, and function bodies need braces {}. Other than that, I don't recall D demanding {}.
Jan 24 2022
On Monday, 24 January 2022 at 17:55:39 UTC, H. S. Teoh wrote:If-statements are another trap waiting to happen... but so far I've found it very hard to resist the conciseness of:That's why I use 'Egyptian braces' with a 'cuddled else': ```D if (x == y) { doSomething(); } else if (y == z) { doSomethingElse(); } else { doYetAnotherThing(); } ``` Not the prettiest, but compact and safe.
Jan 24 2022
On 1/24/22 09:55, H. S. Teoh wrote:as opposed to the verbosity of: if (x == y) { doSomething(); } else if (y == z) { doSomethingElse(); } else { doYetAnotherThing(); }Luckily, humans are very adaptive and can be happy with the following style. ;) if (x == y) { doSomething(); } else if (y == z) { doSomethingElse(); } else { doYetAnotherThing(); } Especially note TABs are only for Makefiles. :p But I can like the following no-brace formatting as well: if (x == y) doSomething(); else if (y == z) doSomethingElse(); else doYetAnotherThing(); Ali
Jan 24 2022
On Mon, Jan 24, 2022 at 10:22:47AM -0800, Ali Çehreli via Digitalmars-d wrote:On 1/24/22 09:55, H. S. Teoh wrote:I used to be a big fan of this style, in fact. But these days, I write in Phobos style -- mainly because at one point I was actively contributing to Phobos and it was just too much of a hassle to have to keep switching mental gears between two divergent styles. After a while, I grew to like the better clarity of the extra whitespace around my code, and stuck to Phobos style ever since. There are still cases where this whitespace becomes excessive, though, and the above code is an example. But to mix the two styles in the same code would be even worse, so for now I'm just gritting my teeth over unbraced if-statements. :-Das opposed to the verbosity of: if (x == y) { doSomething(); } else if (y == z) { doSomethingElse(); } else { doYetAnotherThing(); }Luckily, humans are very adaptive and can be happy with the following style. ;) if (x == y) { doSomething(); } else if (y == z) { doSomethingElse(); } else { doYetAnotherThing(); }Especially note TABs are only for Makefiles. :pI used to be a big fan of tabs. Developed a whole philosophy around why tabs were superior (mainly based around the 80's now-outdated philosophy of saving every last byte because you only had 64K of RAM so every little bit counts). These days, I set expandtab in Vim for all code, and am a lot happier for it. :-P Two-space indentation though... I used to be a big fan of that, in my Perl phase. Needless to say, in retrospect, 2-space indentation + Perl kookiness = completely unreadable code. These days I prefer 4 spaces. (Well OK, that's also the influence of Phobos style, but it's much easier to tell what level you're at with 4-space indentation than with 2-space. And like Torvalds would say, if you need to indent so deep that it's pushing against the right edge of the screen, you're doing something wrong and should refactor your code to avoid that many levels of nesting in the first place. (He was talking about 8-space tab indentation BTW. Though for D code 8-space indentation is a bit too excessive, given the typical nesting level of idiomatic D code.))But I can like the following no-brace formatting as well: if (x == y) doSomething(); else if (y == z) doSomethingElse(); else doYetAnotherThing();[...] This really scares me, because it's also extremely easy to make mistakes (e.g., need to add another line to the else block, so wrap the existing line to a new line and append another line -- while forgetting to add braces). T -- One Word to write them all, One Access to find them, One Excel to count them all, And thus to Windows bind them. -- Mike Champion
Jan 24 2022
On Monday, 24 January 2022 at 17:30:26 UTC, Ali Çehreli wrote:On 1/24/22 04:31, Dennis wrote:Not really a problem in my experience (25 years of C + 5 years of D) it happened only a couple of times and it is quickly found when it happens. I'm an extremly minimalistic programmer, I avoid unecessary parenthesis and brackets whenever I can.I never understood the idea of people always including {}braces inif-statements and for-loops.[...]What idiot would write something like that,Yeah, that thought disappears once one realizes that humans are mistake-making machines. :)One day I had a single-line for-loop body, and to fix an error I quickly added an `import`statement aboveit, pushing the for-loop body outside the for-loop scope.Oops. I've done its counterpart just two days ago by commenting out one line (in somebody else's code): foreach(i; 0..2) // foo(); bar(); Oops! Now bar() is executed multiple times. I am saddened with this skipped-braces "optimization" because all that risk for just to skip writing two characters! Wow! Now... that's... interesting... :) Humans are really interesting...
Jan 24 2022
On Monday, 24 January 2022 at 20:31:36 UTC, Patrick Schluter wrote:I'm an extremly minimalistic programmer, I avoid unecessary parenthesis and brackets whenever I can.Makes sense when your code if finalized and (properly) checked but bugs can be introduced if you haven't finished your code. I find myself doing something like the following: ``` if (val) { one_line_statement(); } else if (other_val) { one_line_statement(); } ``` I think it doesn't take much space and at the same time, it looks very readable.
Jan 25 2022
On Monday, 24 January 2022 at 10:49:36 UTC, Dom DiSc wrote:On Monday, 24 January 2022 at 10:23:14 UTC, rempas wrote:`const` variable are necessary: - in generic code when you don't know if variable is mutable or `immutable`. - if you initialize variable from `const` function parameter or other `const` variables - when you don't want shared variable (`immutable` is implicitly shared, `const` is not). - ...The problem you described is why most language use a "string" type that is immutable (in case you point to a string literal) but they also have a way to allow you to modify a "string" type in case you have allocated memory. So it's always up to you.... I would NEVER EVER declare a variable const. It's always either mutable or immutable. I would go as far as forbidding to declare variables const, it's just confusing and useless. const is only for parameters.
Jan 24 2022
On Monday, 24 January 2022 at 10:23:14 UTC, rempas wrote:On Monday, 24 January 2022 at 10:13:02 UTC, rikki cattermole wrote:Sure thing but that's not realistic if you work professionally as you might be handed code that 15 other people worked on for a decade before you. You will not be able to reason about the memory properly, in which case if certain variables are marked with const it will tell future people that this is read-only memory.If you are working with raw pointers, you need a way to express read only memory. Because the CPU does have it, and if you tried to write to it, bye bye process.We would try to avoid working with pointers directly in read-only memory but in any case, I still think that the programmer should know what they are doing.
Jan 25 2022
On Tuesday, 25 January 2022 at 10:42:35 UTC, bauss wrote:Sure thing but that's not realistic if you work professionally as you might be handed code that 15 other people worked on for a decade before you. You will not be able to reason about the memory properly, in which case if certain variables are marked with const it will tell future people that this is read-only memory.Yeah, the problem with me is that I almost thing about the most cases when you work alone or with good people but never cases like the one you described. The others did an amazing job explain that to me. That and the fact that humans do mistakes even when they know what they are doing...
Jan 25 2022
On Tuesday, 25 January 2022 at 11:40:18 UTC, rempas wrote:On Tuesday, 25 January 2022 at 10:42:35 UTC, bauss wrote:Yeah but it's not the norm, especially not for big companies where many people come and go all the time.Sure thing but that's not realistic if you work professionally as you might be handed code that 15 other people worked on for a decade before you. You will not be able to reason about the memory properly, in which case if certain variables are marked with const it will tell future people that this is read-only memory.Yeah, the problem with me is that I almost thing about the most cases when you work alone or with good people but never cases like the one you described. The others did an amazing job explain that to me. That and the fact that humans do mistakes even when they know what they are doing...
Jan 25 2022
On Tuesday, 25 January 2022 at 10:42:35 UTC, bauss wrote:Sure thing but that's not realistic if you work professionally as you might be handed code that 15 other people worked on for a decade before you. You will not be able to reason about the memory properly, in which case if certain variables are marked with const it will tell future people that this is read-only memory.When saying "we would try to avoid working with read-only memory and pointers directly", I mean the language I'm going to create. So yeah, there will be no code from 10 years ago, I'm pretty sure ;) Aside from the joke, I will keep the fact the a lot of people will work in the same project so having as many protections as possible.
Jan 26 2022
On Thursday, 27 January 2022 at 06:26:43 UTC, rempas wrote:On Tuesday, 25 January 2022 at 10:42:35 UTC, bauss wrote:Yep! I answered two times in the same reply! You will only see that from me! The one and only!Sure thing but that's not realistic if you work professionally as you might be handed code that 15 other people worked on for a decade before you. You will not be able to reason about the memory properly, in which case if certain variables are marked with const it will tell future people that this is read-only memory.When saying "we would try to avoid working with read-only memory and pointers directly", I mean the language I'm going to create. So yeah, there will be no code from 10 years ago, I'm pretty sure ;) Aside from the joke, I will keep the fact the a lot of people will work in the same project so having as many protections as possible.
Jan 26 2022
On Monday, 24 January 2022 at 10:06:49 UTC, rempas wrote:For example, you cannot past "const" variables to functions that take non-const parameters even if we are using variables which are ALWAYS copied (which means than modifying them will not modify the original value).You can? This compiles: ```D struct S { int x; const(int)[] arr; immutable(char)[] str; } void main() { const S sc; immutable S si; f(sc); // mutable copy passed to f f(si); // mutable copy passed to f } void f(S s) { s.x = 3; } ``` It will only error if the type has mutable indirections, because then you could violate `const` by changing the contents behind the array/pointer.
Jan 24 2022
On Monday, 24 January 2022 at 11:15:47 UTC, Dennis wrote:On Monday, 24 January 2022 at 10:06:49 UTC, rempas wrote:I thought I tried it out some months ago and it wasn't possible. Well, turns out that I was wrong about the second part of my post. And that I'm an idiot of course but this is not something I didn't knew before neither something that will stop me....For example, you cannot past "const" variables to functions that take non-const parameters even if we are using variables which are ALWAYS copied (which means than modifying them will not modify the original value).You can? This compiles: ```D struct S { int x; const(int)[] arr; immutable(char)[] str; } void main() { const S sc; immutable S si; f(sc); // mutable copy passed to f f(si); // mutable copy passed to f } void f(S s) { s.x = 3; } ``` It will only error if the type has mutable indirections, because then you could violate `const` by changing the contents behind the array/pointer.
Jan 24 2022
On Monday, 24 January 2022 at 10:06:49 UTC, rempas wrote:Rather than just tell the compiler to not allow me to modify a variable (like I don't know what I'm doing with my program), are there any reason to use "const" variables? Other than out of curiosity, I'm actually asking because I'm writing a transpiler and I want to know if I should support "const" (or the concept of immutability in general) or not. To me, "const" has a lot of burdens like: "should we use it all the time if we don't want to be sure that we won't modify a variable or only for critical ones?" "Then in this case, why not make "const" the default and use another word to allow a variable to be mutable (just like Rust and other languages)?" Also another problem is that I don't like the way "const" is treated in functions. For example, you cannot past "const" variables to functions that take non-const parameters even if we are using variables which are ALWAYS copied (which means than modifying them will not modify the original value). This is stupid because if I want to support "const" for a function, I need to make an extra instruction to copy the value to a new non-const variable that is created inside the function and make an extra instruction. Copying a value is not a slow operation but it can be for a big struct. And in any case, it is stupid and it pisses me off... So yeah, I would like to know as soon as possible if there are any real reasons to support something like that so I can implement it. What do you guys think?AFAIK, const is a contentious topic. You can find many previous discussions on this forum and elsewhere revolving around the questions of how to use const, whether D's const is generally useful, the effect it has on APIs, whether we need tail-const/head-mutable in the language, etc. Jonathan M Davis wrote an article which covers some of these questions (and also considers C++'s const): http://jmdavisprog.com/articles/why-const-sucks.html The article is 4 years old but I don't think much has changed since then. I know that Rust also has const (by default; non-const variable are marked with `mut`) but I don't have enough experience to give an honest opinion on it.
Jan 24 2022
On Monday, 24 January 2022 at 10:06:49 UTC, rempas wrote:What do you guys think?const has utility at interface boundaries. You don't want an API to be used incorrectly. If it's internal code though, it only helps the maintainers, and is often line noise.
Jan 24 2022
On Monday, 24 January 2022 at 14:22:55 UTC, Guillaume Piolat wrote:const has utility at interface boundaries. You don't want an API to be used incorrectly. If it's internal code though, it only helps the maintainers, and is often line noise.I mean, I can understand and agree the cases where people will just make mistakes because they are humans or because they are coding at a time they should be sleeping but like I said, I think that why should start writing good documentation and people should start reading it. Thanks for your thoughts!
Jan 24 2022
On 1/24/22 08:23, rempas wrote:I can understand and agree the cases where people will just make mistakes because they are humansDefinitely.or because they are coding at a time they should be sleepingThat's misleading. Making mistakes is an important part of learning. It happens all the time. That's why we have processes to follow to protect ourselves from ourselves. const, unnecessary (!) curly braces, etc. are parts of such protection. However, const on the function API is also for communication: It tells the caller what parameters are not going to be mutated by the function. But I've become one of the people who advocate 'in' over 'const' especially when compiled with -preview=in: https://dlang.org/spec/function.html#in-params Sweet! 'in' even enables passing rvalues by reference! :) Ali
Jan 24 2022
On 24.01.22 18:47, Ali Çehreli wrote:However, const on the function API is also for communication: It tells the caller what parameters are not going to be mutated by the function. But I've become one of the people who advocate 'in' over 'const' especially when compiled with -preview=in: https://dlang.org/spec/function.html#in-params Sweet! 'in' even enables passing rvalues by reference! :)Actually I am very disappointed that passing rvalues by ref is now tied to transitive const. Makes no sense.
Jan 24 2022
On Monday, 24 January 2022 at 16:23:25 UTC, rempas wrote:On Monday, 24 January 2022 at 14:22:55 UTC, Guillaume Piolat wrote:No, at API level it is also a documentation help. When a parameter is marked as const, the code reader can be sure that there are no side effects in that function on that parameter. This reduces the mental burden when one tries to read code.const has utility at interface boundaries. You don't want an API to be used incorrectly. If it's internal code though, it only helps the maintainers, and is often line noise.I mean, I can understand and agree the cases where people will just make mistakes because they are humans or because they are coding at a time they should be sleeping but like I said, I think that why should start writing good documentation and people should start reading it. Thanks for your thoughts!
Jan 24 2022
On Monday, 24 January 2022 at 20:26:03 UTC, Patrick Schluter wrote:No, at API level it is also a documentation help. When a parameter is marked as const, the code reader can be sure that there are no side effects in that function on that parameter. This reduces the mental burden when one tries to read code.We could also had a library reference documentation that explains that in the worse case. But yeah, "const" works better for this
Jan 25 2022
On 1/24/22 5:06 AM, rempas wrote:Rather than just tell the compiler to not allow me to modify a variable (like I don't know what I'm doing with my program), are there any reason to use "const" variables?If you want the compiler to help you prevent mistakes, yes. If you don't, then no. Other than that, if you want to write a library and have it most accessible to others that may prefer to use const, you should use const, as it will allow the most usage.Other than out of curiosity, I'm actually asking because I'm writing a transpiler and I want to know if I should support "const" (or the concept of immutability in general) or not.immutable/const is purely a compile-time concept. It's not reflected in the final binary, so it's not necessary to forward the attributes to a language that doesn't support it. Same thing with types (see for instance, TypeScript compiled to JavaScript). -Steve
Jan 24 2022
On 1/24/2022 6:40 AM, Steven Schveighoffer wrote:immutable/const is purely a compile-time concept. It's not reflected in the final binary, so it's not necessary to forward the attributes to a language that doesn't support it.Immutable global data gets placed in read-only memory sections. Read-only memory sections are nice in a demand-paged virtual system, as the pages they are in never have to be copied because they are never marked as "dirty".
Jan 24 2022
On Monday, 24 January 2022 at 15:44:54 UTC, Walter Bright wrote:Immutable global data gets placed in read-only memory sections. Read-only memory sections are nice in a demand-paged virtual system, as the pages they are in never have to be copied because they are never marked as "dirty".Read only memory? So in the same place where string literals are placed? This sounds cool and it's really something considerable! Does this offer things like security as date will be able to be created once and not get modified again? I hope I'm not asking for too much...
Jan 24 2022
On 1/24/2022 8:43 AM, rempas wrote:Read only memory? So in the same place where string literals are placed? This sounds cool and it's really something considerable! Does this offer things like security as date will be able to be created once and not get modified again? I hope I'm not asking for too much...You can see this if you run an object file disassembler over the compiler output, the immutable data goes in read-only sections.
Jan 24 2022
On Mon, Jan 24, 2022 at 12:02:11PM -0800, Walter Bright via Digitalmars-d wrote:On 1/24/2022 8:43 AM, rempas wrote:It depends on OS support, obviously. But most commonly-used OSes ought to support this. Placing static string data in the read-only segment could be one line of defense against exploits that, e.g., modify an embedded shell script to do something pernicious instead. T -- Elegant or ugly code as well as fine or rude sentences have something in common: they don't depend on the language. -- Luca De VitisRead only memory? So in the same place where string literals are placed? This sounds cool and it's really something considerable! Does this offer things like security as date will be able to be created once and not get modified again? I hope I'm not asking for too much...You can see this if you run an object file disassembler over the compiler output, the immutable data goes in read-only sections.
Jan 24 2022
On Monday, 24 January 2022 at 20:02:11 UTC, Walter Bright wrote:You can see this if you run an object file disassembler over the compiler output, the immutable data goes in read-only sections.That's actually really amazing and IMO, it is how it should be. Real immutability makes sense rather than just the compiler not letting you mutate the value.
Jan 25 2022
On 1/24/22 10:44 AM, Walter Bright wrote:On 1/24/2022 6:40 AM, Steven Schveighoffer wrote:Sure, but const isn't necessary for that. Const is a compiler construct to prevent you from doing stupid things. But a programming language can run perfectly fine with ROM without having a const concept. D1 put string literals in ROM without const. -Steveimmutable/const is purely a compile-time concept. It's not reflected in the final binary, so it's not necessary to forward the attributes to a language that doesn't support it.Immutable global data gets placed in read-only memory sections. Read-only memory sections are nice in a demand-paged virtual system, as the pages they are in never have to be copied because they are never marked as "dirty".
Jan 24 2022
On 1/24/2022 11:09 AM, Steven Schveighoffer wrote:Sure, but const isn't necessary for that. Const is a compiler construct to prevent you from doing stupid things. But a programming language can run perfectly fine with ROM without having a const concept. D1 put string literals in ROM without const.Yeah, but it's undefined behavior if you write to them.
Jan 24 2022
On 1/24/2022 7:44 AM, Walter Bright wrote:On 1/24/2022 6:40 AM, Steven Schveighoffer wrote:Also, immutable data can be merged together, reducing the memory footprint. The dmd compiler does this with strings, for example. Identical string literals are set up to get merged at link time, this can only happen if they are immutable. Immutable zero initialized data also gets merged. A zero is a zero, no matter what type it is!immutable/const is purely a compile-time concept. It's not reflected in the final binary, so it's not necessary to forward the attributes to a language that doesn't support it.Immutable global data gets placed in read-only memory sections. Read-only memory sections are nice in a demand-paged virtual system, as the pages they are in never have to be copied because they are never marked as "dirty".
Jan 24 2022
On Mon, Jan 24, 2022 at 11:59:37AM -0800, Walter Bright via Digitalmars-d wrote:On 1/24/2022 7:44 AM, Walter Bright wrote:[...]Also, immutable data can be merged together, reducing the memory footprint. The dmd compiler does this with strings, for example. Identical string literals are set up to get merged at link time, this can only happen if they are immutable. Immutable zero initialized data also gets merged. A zero is a zero, no matter what type it is!Makes me curious: how feasible is it to have functions with identical bodies merge together as well? This would help reduce template bloat when you have e.g. a templated type where a bunch of functions are identical because they either don't depend on the type (e.g. a container method that doesn't care about what type the payload is), or else depend on type traits that are common across many types (e.g., int.sizeof which is shared with uint.sizeof, float.sizeof, etc.). T -- Why is it that all of the instruments seeking intelligent life in the universe are pointed away from Earth? -- Michael Beibl
Jan 24 2022
On Monday, 24 January 2022 at 20:09:46 UTC, H. S. Teoh wrote:[snip] Makes me curious: how feasible is it to have functions with identical bodies merge together as well? This would help reduce template bloat when you have e.g. a templated type where a bunch of functions are identical because they either don't depend on the type (e.g. a container method that doesn't care about what type the payload is), or else depend on type traits that are common across many types (e.g., int.sizeof which is shared with uint.sizeof, float.sizeof, etc.). TThis reminds me of generics. In languages with generics, you can get one copy of a function over many different types. My (possibly incorrect) recollection is that it works like having the compiler cast the generic MyClass!T to MyClass. Ideally from D's perspective there would be a way to do this to minimize any overhead that you would get in Java from being forced to use classes. Merging functions with identical bodies is basically the problem that inout is trying to solve. A way to express inout via the language would probably be good, though inout is rather complicated. For instance, you have an Inout(T) with the property that if you have a function that takes an Inout(T), then calling it with Inout!int, Inout!(const(int)), and Inout!(immutable(int)) would all have only one version of a function at runtime. You would still need to be able to enforce that Inout(T) has the same unique behaviors as inout, such as that you can't modify the variable in the body of the function. This would also be useful for reducing template bloat with allocators. For instance, if you have a templated function that takes an allocator as a parameter, then for every different allocator you use with it, you get an extra copy of the function, even if the body of the function may be the same across the different allocators used (since it may be jumping to the allocator to call that code).
Jan 24 2022
On Mon, Jan 24, 2022 at 09:41:28PM +0000, jmh530 via Digitalmars-d wrote:On Monday, 24 January 2022 at 20:09:46 UTC, H. S. Teoh wrote:[...][...]Makes me curious: how feasible is it to have functions with identical bodies merge together as well? This would help reduce template bloat when you have e.g. a templated type where a bunch of functions are identical because they either don't depend on the type (e.g. a container method that doesn't care about what type the payload is), or else depend on type traits that are common across many types (e.g., int.sizeof which is shared with uint.sizeof, float.sizeof, etc.).This reminds me of generics. In languages with generics, you can get one copy of a function over many different types. My (possibly incorrect) recollection is that it works like having the compiler cast the generic MyClass!T to MyClass. Ideally from D's perspective there would be a way to do this to minimize any overhead that you would get in Java from being forced to use classes.IMNSHO, Java generics are weaksauce because they are unable to take advantage of compile-time type information. Basically, once you insert an object of type T into the container, all information about T is erased at runtime, it's just a container of Object, so you couldn't, for example, optimize your container based on the size/alignment of its contents, for example, or use a more compact storage method by inspecting the size of T. The container code can only perform operations that don't introduce a runtime dependency on the specifics of T. D's templates are much more powerful, but that power does come at the price of (sometimes great) template bloat: you get a new copy of the code for every T the template is instantiated with. The ideal best of both worlds is if the D compiler can somehow selectively type-erase the implementation of a template, so that the parts that can be factored out as generic code that works with all T, of which we only need a single instantiation, vs. the type-dependent (non-type-erased) parts which remain as separate instantiations. Merging functions that are binary-identical despite being, at the language level, distinct template instantiations, would be a good step in this direction.Merging functions with identical bodies is basically the problem that inout is trying to solve. A way to express inout via the language would probably be good, though inout is rather complicated. For instance, you have an Inout(T) with the property that if you have a function that takes an Inout(T), then calling it with Inout!int, Inout!(const(int)), and Inout!(immutable(int)) would all have only one version of a function at runtime. You would still need to be able to enforce that Inout(T) has the same unique behaviors as inout, such as that you can't modify the variable in the body of the function.inout is a hack and a crock. I think it's the wrong approach. First of all, inout as currently implemented is incomplete: there are a lot of things you cannot express wrt. inout that you might reasonably want to. For example, inout applied to delegates: it quickly becomes ambiguous what the inout is supposed to refer to: the return type of the delegate, or its parameter, or the outer function's return type, or the outer function's parameter. Inside the function body if you need to hold references to the delegate and/or its parameters, it quickly becomes a total mess (and just plain doesn't compile because the compiler doesn't understand what you're trying to do and the language doesn't let you express what you want to do). Secondly, inout applies only to const/immutable. In generic code, I frequently find myself wishing for inout(nothrow), inout(pure), etc., but the language currently does not support such things. And it's also questionable whether attribute soup + attribute soup with complete sub-grammars is really the right direction to go. Your function declarations quickly drowns in attribute subgrammar and readability goes out the window. Third, inout kinda-sorta behaves like a template except that it isn't one, and it kinda-sorta behaves like Java generics, but without half of the expressiveness. It's a special case of templates with the optimization of identical bodies being merged, but artificially restricted to a single function and to alternation between const/mutable/immutable, and arbitrarily *not* a template so it behaves differently from the template part of the language. A misfit stuck in a very narrow niche that fits in neither with templates nor with generics. IMO the right approach is to just replace inout with templates, let the compiler merge identical function bodies and eliminate template bloat, and let the compiler infer the attribute soup for you so that you don't have to deal with it directly.This would also be useful for reducing template bloat with allocators. For instance, if you have a templated function that takes an allocator as a parameter, then for every different allocator you use with it, you get an extra copy of the function, even if the body of the function may be the same across the different allocators used (since it may be jumping to the allocator to call that code).Exactly. T -- Skill without imagination is craftsmanship and gives us many useful objects such as wickerwork picnic baskets. Imagination without skill gives us modern art. -- Tom Stoppard
Jan 24 2022
On 1/24/2022 12:09 PM, H. S. Teoh wrote:Makes me curious: how feasible is it to have functions with identical bodies merge together as well? This would help reduce template bloat when you have e.g. a templated type where a bunch of functions are identical because they either don't depend on the type (e.g. a container method that doesn't care about what type the payload is), or else depend on type traits that are common across many types (e.g., int.sizeof which is shared with uint.sizeof, float.sizeof, etc.).It's quite feasible. I've considered adding that optimization many times.
Jan 24 2022
On Monday, 24 January 2022 at 20:09:46 UTC, H. S. Teoh wrote:Makes me curious: how feasible is it to have functions with identical bodies merge together as well?Cursory reseach suggests that the main obstacle to this is function pointers. Specifically, if two different functions with identical bodies both have their addresses taken, and the resulting pointers are compared with ==, the result must be `false`. Unless the compiler (or linker, in the case of LTO) can prove that a comparison like this never happens, the optimization is invalid. An easier optimization is to "factor out" the bodies of identical functions into a single new function, and have the original functions simply forward to the new one. For example, when presented with int f(int x, int y) { return x^^2 - y + 42; } int g(int x, int y) { return x^^2 - y + 42; } ...the compiler (or linker) could emit something like int f(int x, int y) { return __generated(x, y); } int g(int x, int y) { return __generated(x, y); } int __generated(int x, int y) { return x^^2 - y + 42; } With tail-call optimization, the overhead of the additional function call is extremely small.
Jan 24 2022
On Monday, 24 January 2022 at 14:40:33 UTC, Steven Schveighoffer wrote:On 1/24/22 5:06 AM, rempas wrote:Thanks for your time! My question is if you think that it will be very very bad to not include it in my language or not. I'm slowly changing my mind after seeing all these comments and thinking about including it tho...Rather than just tell the compiler to not allow me to modify a variable (like I don't know what I'm doing with my program), are there any reason to use "const" variables?If you want the compiler to help you prevent mistakes, yes. If you don't, then no. Other than that, if you want to write a library and have it most accessible to others that may prefer to use const, you should use const, as it will allow the most usage.Other than out of curiosity, I'm actually asking because I'm writing a transpiler and I want to know if I should support "const" (or the concept of immutability in general) or not.immutable/const is purely a compile-time concept. It's not reflected in the final binary, so it's not necessary to forward the attributes to a language that doesn't support it. Same thing with types (see for instance, TypeScript compiled to JavaScript). -Steve
Jan 24 2022
On 1/24/22 11:27 AM, rempas wrote:Thanks for your time! My question is if you think that it will be very very bad to not include it in my language or not. I'm slowly changing my mind after seeing all these comments and thinking about including it tho...Some newer languages are gravitating towards const by default. For example, Swift by default takes parameters as constants. You used to be able to take them with the `var` designation, but now you have to declare a new variable in the function if you want to have a mutable copy. If you declare a variable with `var` and don't mutate it, the compiler complains that you really should use `let` (the const equivalent). The advantages of const to prevent mistakes definitely exist, and most people appreciate it. That being said I generally don't use it unless I think of it, or I have to for a library to work. -Steve
Jan 24 2022
On 1/24/2022 2:06 AM, rempas wrote:Also another problem is that I don't like the way "const" is treated in functions. For example, you cannot past "const" variables to functions that take non-const parameters even if we are using variables which are ALWAYS copiedNot sure what you mean. This compiles: int foo(const int); int bar(int i) { return foo(i); }
Jan 24 2022
On Monday, 24 January 2022 at 15:40:56 UTC, Walter Bright wrote:Not sure what you mean. This compiles: int foo(const int); int bar(int i) { return foo(i); }Actually this compiles but what I thought that didn't was something like this: ``` void mul_num(int num) { num *= 2; } void main() { const int number = 10; mul_num(number); } ``` But it turns out that it compiles but I would swear that I tried something similar to this and it wouldn't compile on both D and C.
Jan 24 2022
On 1/24/22 11:41 AM, rempas wrote:On Monday, 24 January 2022 at 15:40:56 UTC, Walter Bright wrote:I know exactly what you were doing: ```d void mul_num(T)(T num) { num *= 2; } ``` That will fail if you just do `mul_num(number)` because templates infer the type from the argument (e.g. T becomes `const int`) Unfortunately, D doesn't have a "tail-const" modifier, which would work really well here. -SteveNot sure what you mean. This compiles: Â int foo(const int); Â int bar(int i) Â { Â Â Â return foo(i); Â }Actually this compiles but what I thought that didn't was something like this: ``` void mul_num(int num) { Â num *= 2; } void main() { Â const int number = 10; Â mul_num(number); } ``` But it turns out that it compiles but I would swear that I tried something similar to this and it wouldn't compile on both D and C.
Jan 24 2022
On Monday, 24 January 2022 at 19:15:42 UTC, Steven Schveighoffer wrote:I know exactly what you were doing: ```d void mul_num(T)(T num) { num *= 2; } ``` That will fail if you just do `mul_num(number)` because templates infer the type from the argument (e.g. T becomes `const int`) Unfortunately, D doesn't have a "tail-const" modifier, which would work really well here. -SteveYeah right, now I remember! I did it about 2 months ago in a template function that converts types and It didn't compiled. Now, I know why, thank you!
Jan 25 2022
On Monday, 24 January 2022 at 10:06:49 UTC, rempas wrote:.. What do you guys think?Well, if const were default, you could ask yourself, is there any real reason to use mutable :-) If I see a function: void getuser(string pwd){} .. I get kinda concerned. If I write a function: void getuser(string pwd){} .. I also get kinda concerned. After hours of debugging, you eventually realise the root of your problem, was that pwd was not const. Constraints on parameters help to ensure correctness. That is the value of const. I wish safe and const were default actually.
Jan 24 2022