digitalmars.D - A Philosophy of Software Design
- Walter Bright (24/24) May 23 by John Ousterhout
- Walter Bright (5/5) May 23 The first sentence of the chapter "Define Errors Out Of Existence" says:
- Richard (Rikki) Andrew Cattermole (11/19) May 23 I've been attempting to find a way to do that for 3+ years.
- Walter Bright (19/19) May 23 Thanks. This is an interesting general purpose method.
- Richard (Rikki) Andrew Cattermole (18/28) May 23 Where possible yes, you should remove the possibility of needing to
- Richard (Rikki) Andrew Cattermole (11/44) May 23 Code Complete 2nd edition has three chapters about error handling,
- Richard (Rikki) Andrew Cattermole (23/71) May 23 "If you have the luxury of designing an API, design it in such a way
- Walter Bright (20/20) May 23 Microsoft is not wrong. You're not wrong, either.
- Richard (Rikki) Andrew Cattermole (48/73) May 23 My PoV is that you gotta use the right tool for the job.
- Walter Bright (13/37) May 24 See the book I suggested, "A Philosophy of Software Design", which shows...
- Walter Bright (1/1) May 23 BTW, I ordered the 3 books. Thanks!
- Richard (Rikki) Andrew Cattermole (8/11) May 23 That's not actually how you handled it, although I'm sure it solved some...
- Basile B. (16/28) May 24 I think a better example is when in expsema the type of an
- Walter Bright (5/13) May 26 What the Error nodes did was eliminate the cascade of error messages res...
- Paul Backus (19/34) May 24 This is one way to define exceptions out of existence: expand the
- Walter Bright (8/24) May 24 The idea is to reduce complexity by not having separate error paths entw...
- H. S. Teoh (31/41) May 24 You convinced me that macros are a terrible idea. :-D Actually, you
- Dom Disc (8/11) May 25 This is why I always suggested a NaN value for all types. For
- Walter Bright (3/9) May 25 Unfortunately, since integer arithmetic may use T.min, it's not going to...
- Basile B. (4/18) May 26 Bollocks. Here you are mistalind software errors with how a
- H. S. Teoh (9/18) May 24 On the contrary, you yourself said back in the day that exception
- Walter Bright (20/25) May 24 Yes, I did say that. But as I also wrote, my thinking has evolved over t...
- H. S. Teoh (60/94) May 24 IMO, the problems stem from conflating these two distinct operations
- Walter Bright (12/22) May 24 You do have a point. However, it's much easier to put a single error che...
- H. S. Teoh (29/40) May 25 The current implementation of writefln leaves a lot of room for
- Richard (Rikki) Andrew Cattermole (5/51) May 25 There is a simple way to archive this, use IES.
- H. S. Teoh (7/19) May 25 [...]
- Richard (Rikki) Andrew Cattermole (2/23) May 25 https://dlang.org/spec/istring.html
- Dejan Lekic (4/8) May 25 100%
- Zz (4/12) May 24 Might find this interesting.
- Kapendev (14/16) May 24 The error to read a file in Odin:
- Walter Bright (3/4) May 24 "OOOOdddiiiiinnnn!!!!"
- Basile B. (6/20) May 28 That's a good challenge, really. The problem I have with that
- H. S. Teoh (20/29) May 28 [...]
- libxmoc (17/17) May 24 AI elevates great architects but empowers unqualified users to
- libxmoc (3/3) May 24 Do not get me wrong, I am pro AI, I advocate for automating
- Walter Bright (2/5) May 24 AI is just another tool.
- Walter Bright (2/3) May 24 That's against our policy.
- matheus (18/23) May 24 I haven't vibe coding as well, but I have being using it to
- Walter Bright (2/4) May 24 A wise decision. I wouldn't put my airplane on autopilot so I could go t...
- Lance Bachmeier (18/25) May 24 I haven't read that book, but Ousterhout has made the same point
- Walter Bright (6/21) May 24 You are correct that it is not necessary. However, I recognize a number ...
- Lance Bachmeier (6/23) May 25 The limit of 60 lines is for the LLM. It hadn't even entered my
- Walter Bright (3/7) May 25 This is conventional wisdom, but the book argues against it, based in th...
- Dejan Lekic (3/5) May 24 This book is what quite few well-known AI gurus mentioned lately
- Walter Bright (2/4) May 24 That's how I found out about it!
- Meta (21/27) May 24 I dunno, I don't really agree with this point of view. If your
- Walter Bright (7/26) May 25 I never saw it fail in practice. You'd have to write a string that was m...
- Walter Bright (10/10) May 25 I forgot to mention - an out of memory error is nearly always a fatal er...
- Meta (10/21) May 25 Ah yes, okay, that's at least better than a cryptic "out of
- Meta (7/21) May 25 Okay, fair enough. I can't ever recall seeing strings that large
- Indraj Gandham (15/15) May 25 About error handling:
- H. S. Teoh (13/16) May 25 [...]
- Guillaume Piolat (23/27) May 25 My own understanding of it at the moment is that there are many
by John Ousterhout https://www.amazon.com/Philosophy-Software-Design-2nd/dp/173210221X I did not know it, but I've been looking for this book for a long time. I'm about halfway through it. It's about managing software complexity. Complexity is the bane of all significant software. Over the years I have battled it, and have circled into many of the techniques described in the book. Those who have seen my talks know that a recurring focus is how to use D to manage software complexity. This book is an easy read, and only $10. It's worth far more. For example, the title of Chapter 10 is "Define Errors out of Existence". I've been trying to do that since the 1980s. Back in the 80's, a C compiler was required to support strings of at least NNN characters in length. So most C compilers would put a check in for that, and issue an error message on overflow, and then recover from the error. My compiler took a different approach. It would just keep enlarging the string buffer until it ran out of memory. Then there was only one error message - "out of memory" - and the compiler would abort. This applied to all sorts of arbitrary limits the C spec placed on things. There was no need to add error recovery code. But still, the D compiler is overly complex, and so is Phobos. We've still got a lot to learn. I've not vibe coded enough to see it for myself, but I've been told that AI generated code simply generates code until it works. It doesn't do very well at managing complexity. Something to watch out for.
May 23
The first sentence of the chapter "Define Errors Out Of Existence" says: "Exception handling is one of the worst sources of complexity in software systems." I suspect that adding EH to D was a mistake. It certainly was a mistake to build it into Unicode string handling. I'd like to see if we can figure a way to do Phobos without exception handling.
May 23
On 24/05/2026 1:42 PM, Walter Bright wrote:The first sentence of the chapter "Define Errors Out Of Existence" says: "Exception handling is one of the worst sources of complexity in software systems." I suspect that adding EH to D was a mistake. It certainly was a mistake to build it into Unicode string handling. I'd like to see if we can figure a way to do Phobos without exception handling.I've been attempting to find a way to do that for 3+ years. Unfortunately you made it so that we can't do value type exceptions. Aka the compiler converts the throw set + return type into a sum type. That requires inferring to work, and nothrow is now on the chopping block due to that. Which leaves us with result types and unwrapping. This is my solution to the problem (please ignore the unwrap alias stuff I did later on, I want to kill that but thats a political problem): https://forum.dlang.org/post/vcozmhysmztnmngzopnm forum.dlang.org This also handles errors without a result type.
May 23
Thanks. This is an interesting general purpose method. But the book suggests a different approach in the title - define them out of existence. I've also thought of various general replacement schemes for exceptions. The difficulty with exceptions is they are complicated. It's difficult to figure out what path the code execution goes through when there are various exceptions. The exception paths are also a rich source of bugs because they are untested and may never trigger. Some examples of defining them out of existence: 1. The C Standard says the compiler must support n characters in a string literal. Implementing this involves detecting the overflow, issuing an error message, and then recovering. A define-out-of-existence approach, which I've always used, is just keep mallocing memory until the memory allocator fails - and then abort the program with "out of memory". You'll see this in the compiler code. 2. Instead of throwing an exception when encountering an invalid code point, the unicode handler should substitute in an "invalid character" code point. This behaves much like a floating point NaN value. 3. Invalid code nodes are replaced with "Error" nodes. This worked far better than I anticipated. No exceptions are thrown. It also behaves like NaN.
May 23
On 24/05/2026 4:10 PM, Walter Bright wrote:Thanks. This is an interesting general purpose method. But the book suggests a different approach in the title - define them out of existence. I've also thought of various general replacement schemes for exceptions. The difficulty with exceptions is they are complicated. It's difficult to figure out what path the code execution goes through when there are various exceptions. The exception paths are also a rich source of bugs because they are untested and may never trigger.Where possible yes, you should remove the possibility of needing to handle the error case. But you can't always do this especially for a standard library. It's far more on the rare side to have a problem where you can do it for and there are enough cases even in UTF/Unicode to want it to produce an error that you must handle. An awful lot of application development is based upon the principle of log + finalize outputs + kill task. And that requires some method of unwinding, either implicitly via EH or explicitly via result types. It is fairly well known and has been taught in software engineering for a long time to avoid unnecessary logic like error handling here. "Do any of your functions return error values? Is it possible to redefine those functions to eliminate the error conditions? Remember that when a function returns an error, that error must be handled - or mishandled - at every point of call." Writing Solid Code, Page 198, Copyright 1993. https://www.amazon.com/Writing-Solid-Code-Microsoft-Programming/dp/1556155514
May 23
On 24/05/2026 4:27 PM, Richard (Rikki) Andrew Cattermole wrote:On 24/05/2026 4:10 PM, Walter Bright wrote:Code Complete 2nd edition has three chapters about error handling, including one for exceptions and another for asserts. This includes a brief discussion on each of: return a neutral value (not a character), error codes, log/error message, kill process. Copyright 2004, Page 194, https://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670 This is taught at tertiary education for programming. My copy was bought because it was required reading. Note that CS courses may not cover this, but programming and software engineering qualifications should.Thanks. This is an interesting general purpose method. But the book suggests a different approach in the title - define them out of existence. I've also thought of various general replacement schemes for exceptions. The difficulty with exceptions is they are complicated. It's difficult to figure out what path the code execution goes through when there are various exceptions. The exception paths are also a rich source of bugs because they are untested and may never trigger.Where possible yes, you should remove the possibility of needing to handle the error case. But you can't always do this especially for a standard library. It's far more on the rare side to have a problem where you can do it for and there are enough cases even in UTF/Unicode to want it to produce an error that you must handle. An awful lot of application development is based upon the principle of log + finalize outputs + kill task. And that requires some method of unwinding, either implicitly via EH or explicitly via result types. It is fairly well known and has been taught in software engineering for a long time to avoid unnecessary logic like error handling here. "Do any of your functions return error values? Is it possible to redefine those functions to eliminate the error conditions? Remember that when a function returns an error, that error must be handled - or mishandled - at every point of call." Writing Solid Code, Page 198, Copyright 1993. https://www.amazon.com/Writing-Solid-Code-Microsoft- Programming/dp/1556155514
May 23
On 24/05/2026 5:02 PM, Richard (Rikki) Andrew Cattermole wrote:On 24/05/2026 4:27 PM, Richard (Rikki) Andrew Cattermole wrote:"If you have the luxury of designing an API, design it in such a way that it minimizes the amount of error handling that is required, if at all possible. In addition, try to design APIs so that failures are not potentially critical if they go unhandled. Otherwise, appropriate exception handling can help you ensure that no errors that go unhandled will propagate dangers error conditions. Use wrappers to convert functions that may fail with traditional error code, so that they instead use exception handling." - Secure Programming Cookbook, Copyright 2003, https://www.amazon.com/Secure-Programming-Cookbook-Cryptography-Authentication/dp/0596003943 The more appropriate solution for D, is to use a struct that wraps the value: ```d struct ErrorCode { int code; } ``` Treat this like any result type, with opCast and mustuse rather than using exception handling. Because it doesn't supply a value, you don't need the opUnwrapIfTrue in this particular case. Ideally we could swap 1:1 at the function prototype, but LLVM will error if you try to do this, so that is a potential improvement we could have.On 24/05/2026 4:10 PM, Walter Bright wrote:Code Complete 2nd edition has three chapters about error handling, including one for exceptions and another for asserts. This includes a brief discussion on each of: return a neutral value (not a character), error codes, log/error message, kill process. Copyright 2004, Page 194, https://www.amazon.com/Code-Complete-Practical-Handbook- Construction/dp/0735619670 This is taught at tertiary education for programming. My copy was bought because it was required reading. Note that CS courses may not cover this, but programming and software engineering qualifications should.Thanks. This is an interesting general purpose method. But the book suggests a different approach in the title - define them out of existence. I've also thought of various general replacement schemes for exceptions. The difficulty with exceptions is they are complicated. It's difficult to figure out what path the code execution goes through when there are various exceptions. The exception paths are also a rich source of bugs because they are untested and may never trigger.Where possible yes, you should remove the possibility of needing to handle the error case. But you can't always do this especially for a standard library. It's far more on the rare side to have a problem where you can do it for and there are enough cases even in UTF/Unicode to want it to produce an error that you must handle. An awful lot of application development is based upon the principle of log + finalize outputs + kill task. And that requires some method of unwinding, either implicitly via EH or explicitly via result types. It is fairly well known and has been taught in software engineering for a long time to avoid unnecessary logic like error handling here. "Do any of your functions return error values? Is it possible to redefine those functions to eliminate the error conditions? Remember that when a function returns an error, that error must be handled - or mishandled - at every point of call." Writing Solid Code, Page 198, Copyright 1993. https://www.amazon.com/Writing-Solid-Code-Microsoft- Programming/dp/1556155514
May 23
Microsoft is not wrong. You're not wrong, either. But consider the copyright dates on the books: 1993, 2003, 2004. I know my ideas on what is better certainly have evolved over the years. A number of problems have come up with exceptions. I suppose it's like macros - they are a great idea, until you've used them for 10 years, and then they don't look so good. Let's take Unicode again. The current method in Phobos is autodecode, which turned out to be a bad idea. It also throws an exception on malformed code points. The first problem is you cannot use any string code in Phobos without supporting exceptions and memory allocations. The second problem is throwing an exception is the wrong solution. Consider displaying text in your editor. Do you want the editor to throw an exception if the text has bad code points in it? Do you want the browser to throw an exception if the html has bad code points in it? No. Better to render the bad code point as the invalid code point. If you really, really need to throw an exception, run the text through a *separate* filter to throw when it sees an invalid code point. (Personally, I really do not want my string handling functions throwing exceptions. Like searching for a substring - what good would an exception be?) Anyhow, I recommend checking the book I mentioned. It's only ten bucks! I'm pretty sure it will be worth your while.
May 23
On 24/05/2026 5:57 PM, Walter Bright wrote:Microsoft is not wrong. You're not wrong, either.My PoV is that you gotta use the right tool for the job. Each strategy has its own strengths and weaknesses, and all of them should be supported. As required.But consider the copyright dates on the books: 1993, 2003, 2004. I know my ideas on what is better certainly have evolved over the years. A number of problems have come up with exceptions. I suppose it's like macros - they are a great idea, until you've used them for 10 years, and then they don't look so good.In this particular case, the ideas presented in those books haven't evolved since then. And the conclusion is to use a mix of strategies based upon what the code needs to do. I've done plenty of research over the past few years on the topic, and haven't found anything notable.Let's take Unicode again. The current method in Phobos is autodecode, which turned out to be a bad idea. It also throws an exception on malformed code points.Funny that you mention that. "When a conversion algorithm encounters such unconvertible data, the usual practice is either to throw an exception or to use a defined substitution character to represent the unconvertible data. In the case of conversion to one of the encoding forms of the Unicode Standard, the substitution character is defined as U+FFFD REPLACEMENT CHARACTER. For conversion between different encoding forms of the Unicode Standard, “U+FFFD Substitution of Maximal Subparts” in Section 3.9, Unicode Encoding Forms defines a practice for the use of U+FFFD which is consistent with the W3C standard for encoding. It is useful to apply the same practice to the conversion from non-Unicode encodings to an encoding form of the Unicode Standard. This practice is more secure because it does not result in the conversion consuming parts of valid sequences as though they were invalid. It also guarantees at least one replacement character will occur for each instance of an invalid sequence in the original text. Furthermore, this practice can be defined consistently for better interoperability between different implementations of conversion." - Unicode standard 17, page 323, 5.22 U+FFFD Substitution in Conversion. https://www.unicode.org/versions/Unicode17.0.0/UnicodeStandard-17.0.pdf TLDR: exceptions and replacement characters are both nominal approaches in Unicode handling.The first problem is you cannot use any string code in Phobos without supporting exceptions and memory allocations. The second problem is throwing an exception is the wrong solution.It is not necessarily the wrong decision, which is why its so predominant. We have had trouble with it sure, and we would like to change it. But the problem domain does suggest it /can/ be the right choice. Even if I personally wouldn't do it with exceptions. There are some very nice boundaries in the algorithms and plenty of opportunities for specialization of functions including of decoding for specific error handling requirements.Consider displaying text in your editor. Do you want the editor to throw an exception if the text has bad code points in it? Do you want the browser to throw an exception if the html has bad code points in it? No. Better to render the bad code point as the invalid code point.If that exception is escaping the editor component rendering and causing the program to crash, that is a MAJOR BUG. Exceptions are supposed to be caught and handled much more locally in components like this, if there is potential for them to be thrown. Under no circumstances should that exception impact the user beyond a error alert. You should try Intellij out some time, sadly the D plugin still produces exceptions but yet its still quite functional. When applications are written properly, they handle exceptions gracefully and don't just fail at the first bad input.If you really, really need to throw an exception, run the text through a *separate* filter to throw when it sees an invalid code point. (Personally, I really do not want my string handling functions throwing exceptions. Like searching for a substring - what good would an exception be?) Anyhow, I recommend checking the book I mentioned. It's only ten bucks! I'm pretty sure it will be worth your while.I considered it, but the $70 price tag ended that thought process beyond adding to a wish list lol.
May 23
On 5/23/2026 11:18 PM, Richard (Rikki) Andrew Cattermole wrote:In this particular case, the ideas presented in those books haven't evolved since then.See the book I suggested, "A Philosophy of Software Design", which shows an evolved understanding.TLDR: exceptions and replacement characters are both nominal approaches in Unicode handling.I cannot say I automatically accept programming advice from the Unicode people. After all, they invented normalized code points, an astonishingly bad idea. I've never encountered anyone able to defend it beyond 2 rounds.It was the wrong decision. Even Andrei came around on this, to his great credit.The first problem is you cannot use any string code in Phobos without supporting exceptions and memory allocations. The second problem is throwing an exception is the wrong solution.It is not necessarily the wrong decision, which is why its so predominant.We have had trouble with it sure, and we would like to change it. But the problem domain does suggest it /can/ be the right choice. Even if I personally wouldn't do it with exceptions. There are some very nice boundaries in the algorithms and plenty of opportunities for specialization of functions including of decoding for specific error handling requirements.I'm not convinced. I've never found any utility in generating exceptions on Unicode decoding.If that exception is escaping the editor component rendering and causing the program to crash, that is a MAJOR BUG. Exceptions are supposed to be caught and handled much more locally in components like this, if there is potential for them to be thrown. Under no circumstances should that exception impact the user beyond a error alert. You should try Intellij out some time, sadly the D plugin still produces exceptions but yet its still quite functional. When applications are written properly, they handle exceptions gracefully and don't just fail at the first bad input.Yes, you can write Exception handling correctly and it will behave as required. But that's not the point. The point is it is an over-complication and exposes dirty laundry when trying to encapsulate the functionality of a module.I considered it, but the $70 price tag ended that thought process beyond adding to a wish list lol.$9.99 for the Kindle version. $22.95 for paperback.
May 24
On 24/05/2026 4:10 PM, Walter Bright wrote:Invalid code nodes are replaced with "Error" nodes. This worked far better than I anticipated. No exceptions are thrown. It also behaves like NaN.That's not actually how you handled it, although I'm sure it solved some problems much more easily. You handled it by checking the error count. In other words a global flag. https://github.com/dlang/dmd/blob/3c2ad72ad3be9c38c76569ccd1574e39fec2256d/compiler/src/dmd/typesem.d#L4787 https://github.com/dlang/dmd/blob/3c2ad72ad3be9c38c76569ccd1574e39fec2256d/compiler/src/dmd/globals.d#L368 If you can get an error node without an error message that is an ICE that should have been emitted but wasn't.
May 23
On Sunday, 24 May 2026 at 06:49:28 UTC, Richard (Rikki) Andrew Cattermole wrote:On 24/05/2026 4:10 PM, Walter Bright wrote:I think a better example is when in expsema the type of an expression is set to Terror. 1. This avoids plenty of null checks 2. This poisons the AST, so that, for example, further conversions wont pass What you put links on is rather the system used for error recovery. Generally I find that error gagging is clumsy but that is casually required (`__traits(compiles)`, `typeof()`, selection in an overload set, SFINAE, etc.) But finally I dont really see how exceptions are related to compiler errors. I've never seen a compiler using them for notifying invalid input code. Invalid input code is unrelated to compiler "as a software" errors (e.g a input file that does not exist).Invalid code nodes are replaced with "Error" nodes. This worked far better than I anticipated. No exceptions are thrown. It also behaves like NaN.That's not actually how you handled it, although I'm sure it solved some problems much more easily. You handled it by checking the error count. In other words a global flag. https://github.com/dlang/dmd/blob/3c2ad72ad3be9c38c76569ccd1574e39fec2256d/compiler/src/dmd/typesem.d#L4787 https://github.com/dlang/dmd/blob/3c2ad72ad3be9c38c76569ccd1574e39fec2256d/compiler/src/dmd/globals.d#L368 If you can get an error node without an error message that is an ICE that should have been emitted but wasn't.
May 24
On 5/23/2026 11:49 PM, Richard (Rikki) Andrew Cattermole wrote:On 24/05/2026 4:10 PM, Walter Bright wrote:What the Error nodes did was eliminate the cascade of error messages resulting from the compiler trying to recover by guessing what the user intended. In other words, the Error nodes were for error recovery. The global flag was not about error reporting or recovery.Invalid code nodes are replaced with "Error" nodes. This worked far better than I anticipated. No exceptions are thrown. It also behaves like NaN.That's not actually how you handled it, although I'm sure it solved some problems much more easily. You handled it by checking the error count. In other words a global flag.
May 26
On Sunday, 24 May 2026 at 04:10:31 UTC, Walter Bright wrote:Some examples of defining them out of existence: 1. The C Standard says the compiler must support n characters in a string literal. Implementing this involves detecting the overflow, issuing an error message, and then recovering. A define-out-of-existence approach, which I've always used, is just keep mallocing memory until the memory allocator fails - and then abort the program with "out of memory". You'll see this in the compiler code. 2. Instead of throwing an exception when encountering an invalid code point, the unicode handler should substitute in an "invalid character" code point. This behaves much like a floating point NaN value. 3. Invalid code nodes are replaced with "Error" nodes. This worked far better than I anticipated. No exceptions are thrown. It also behaves like NaN.This is one way to define exceptions out of existence: expand the range of possible output values to include new values that represent errors (e.g., NaNs, Error nodes, failure states of Result/Option types). This pushes responsibility for handling those new values onto downstream code, which now has to include checks for isNan, isError, and so on. The other way is to restrict the range of possible *inputs* to the function, so that the specific inputs that would cause an exception to be thrown are no longer possible. For example, you could have your string-handling function take a ValidatedString as its input instead of a plain string, and design the public API of ValidatedString to ensure that you can only create one from a string whose code points are all valid. This pushes the responsibility for handling invalid code points onto upstream code. What these approaches have in common is that neither one actually removes the need for error handling. They just change where the error is handled.
May 24
On 5/24/2026 8:36 AM, Paul Backus wrote:This is one way to define exceptions out of existence: expand the range of possible output values to include new values that represent errors (e.g., NaNs, Error nodes, failure states of Result/Option types). This pushes responsibility for handling those new values onto downstream code, which now has to include checks for isNan, isError, and so on. The other way is to restrict the range of possible *inputs* to the function, so that the specific inputs that would cause an exception to be thrown are no longer possible. For example, you could have your string-handling function take a ValidatedString as its input instead of a plain string, and design the public API of ValidatedString to ensure that you can only create one from a string whose code points are all valid. This pushes the responsibility for handling invalid code points onto upstream code. What these approaches have in common is that neither one actually removes the need for error handling. They just change where the error is handled.The idea is to reduce complexity by not having separate error paths entwined through the code in visible and invisible ways. For example, printf has to deal with errors in stdout. That adds significant complexity to printf, with or without exceptions. I do understand that what I am writing here is unconventional and hence obviously wrong. I don't expect to convince anyone easily, just like I am unable to convince people that macros are a terrible misfeature :-/
May 24
On Sun, May 24, 2026 at 02:15:47PM -0700, Walter Bright via Digitalmars-d wrote: [...]The idea is to reduce complexity by not having separate error paths entwined through the code in visible and invisible ways. For example, printf has to deal with errors in stdout. That adds significant complexity to printf, with or without exceptions. I do understand that what I am writing here is unconventional and hence obviously wrong. I don't expect to convince anyone easily, just like I am unable to convince people that macros are a terrible misfeature :-/You convinced me that macros are a terrible idea. :-D Actually, you didn't need to do much convincing. Having experienced them myself, and having to work with them every now and then at work (which involves a (very) large mostly-C/C++ codebase), and also having written a winning entry for the IOCCC with a fair amount of macro abuse, I've seen what they're capable of, and also what horrors they can bring. It didn't take much to convince me there are better ways of solving problems. As far as error-handling is concerned, I find exceptions very useful in my own code, where they help to keep the main logic clear, and separate out the messy error-handling stuff into a separate place without cluttering the main algorithm. IME the more straightforward the main logic is, the less likely there are bugs. The more error-handling you have to insert inline, the more places there are for bugs to hide. Throwing an exception to abort a complex calculation is better than sprinkling tons of `if (value.isNaN)` all over your code, or whatever its equivalent is (error node, null value, etc). But if you're finding yourself having to write tons of catch blocks everywhere, then you're doing something wrong. Then it's no better than sprinkling `if (x is null)` or `if (x.isNaN)` everywhere. In general, I find that exceptions should mostly be used only to signal conditions worthy of aborting an operation entirely, cases where you basically print a message to the console and abort the process or similar. Less extreme conditions often don't deserve an exception. I'd even go so far as to say that if your catch block is more than just logging an error message and signalling failure (abort program, abort current operation, etc.), you're doing something wrong. T -- Sometimes the best solution to morale problems is just to fire all of the unhappy people. -- despair.com
May 24
On Sunday, 24 May 2026 at 04:10:31 UTC, Walter Bright wrote:3. Invalid code nodes are replaced with "Error" nodes. This worked far better than I anticipated. No exceptions are thrown. It also behaves like NaN.This is why I always suggested a NaN value for all types. For signed integers the unfortunate T.min (0x80..00) which has no positive counterpart is the perfect candidate for NaN. Unsigned types doesn't have such a good candidate - for sure, most calculations that try to prevent overflows are very unlikely to return 0xFF..FF as result, nevertheless this is a valid result. So defining T.max as NaN is possible but ugly.
May 25
On 5/25/2026 5:14 AM, Dom Disc wrote:This is why I always suggested a NaN value for all types. For signed integers the unfortunate T.min (0x80..00) which has no positive counterpart is the perfect candidate for NaN. Unsigned types doesn't have such a good candidate - for sure, most calculations that try to prevent overflows are very unlikely to return 0xFF..FF as result, nevertheless this is a valid result. So defining T.max as NaN is possible but ugly.Unfortunately, since integer arithmetic may use T.min, it's not going to work as a NaN value.
May 25
On Sunday, 24 May 2026 at 04:10:31 UTC, Walter Bright wrote:Thanks. This is an interesting general purpose method. But the book suggests a different approach in the title - define them out of existence. I've also thought of various general replacement schemes for exceptions. The difficulty with exceptions is they are complicated. It's difficult to figure out what path the code execution goes through when there are various exceptions. The exception paths are also a rich source of bugs because they are untested and may never trigger. Some examples of defining them out of existence: [...] 3. Invalid code nodes are replaced with "Error" nodes. This worked far better than I anticipated. No exceptions are thrown. It also behaves like NaN.Bollocks. Here you are mistalind software errors with how a compiler must handle wrong input. This third example is not a good one.
May 26
On Sat, May 23, 2026 at 06:42:43PM -0700, Walter Bright via Digitalmars-d wrote:The first sentence of the chapter "Define Errors Out Of Existence" says: "Exception handling is one of the worst sources of complexity in software systems." I suspect that adding EH to D was a mistake. It certainly was a mistake to build it into Unicode string handling. I'd like to see if we can figure a way to do Phobos without exception handling.On the contrary, you yourself said back in the day that exception handling was a good idea because it forced the program to stop upon encountering an I/O error. As opposed to a C program ignoring the return value of printf(), et al, and blindly barging forward when an unexpected condition like a disk full error started happening. T -- "If this is the solution, I want my precipitate back."
May 24
On 5/24/2026 7:51 AM, H. S. Teoh wrote:On the contrary, you yourself said back in the day that exception handling was a good idea because it forced the program to stop upon encountering an I/O error. As opposed to a C program ignoring the return value of printf(), et al, and blindly barging forward when an unexpected condition like a disk full error started happening.Yes, I did say that. But as I also wrote, my thinking has evolved over time and experience. printf does two things: 1. format arguments into a character stream 2. write the stream to stdout. So, I have advocated the "sink" or "output range" approach, which would look like this: ``` printf(sink, format, args...); ``` printf shouldn't know anything about sink, it should just send the characters to it. You can see this in the dmd implementation, where OutBuffer is the sink for formatted characters, and ErrorSink is used to accept messages about errors. By consolidating output into sinks, one does not have to check for an error at every invocation of printf. I still use printf in dmd, but only for the porpoise of printing debugging information so I can debug the compiler. I use snprintf() for when things matter, because snprintf() accepts a (primitive) sink as an argument.
May 24
On Sun, May 24, 2026 at 02:00:35PM -0700, Walter Bright via Digitalmars-d wrote:On 5/24/2026 7:51 AM, H. S. Teoh wrote:IMO, the problems stem from conflating these two distinct operations into one. Formatting a character stream doesn't have anything to do with writing to stdout. The former involves manipulating string data in-memory; the latter is involves interacting with the OS and doing I/O, which is always prone to errors and unexpected conditions. The correct approach is to separate the two operations, which is essentially what you propose:On the contrary, you yourself said back in the day that exception handling was a good idea because it forced the program to stop upon encountering an I/O error. As opposed to a C program ignoring the return value of printf(), et al, and blindly barging forward when an unexpected condition like a disk full error started happening.Yes, I did say that. But as I also wrote, my thinking has evolved over time and experience. printf does two things: 1. format arguments into a character stream 2. write the stream to stdout.So, I have advocated the "sink" or "output range" approach, which would look like this: ``` printf(sink, format, args...); ``` printf shouldn't know anything about sink, it should just send the characters to it.This is equivalent to separating concerns: printf is concerned with formatting and only formatting; writing the output is handled by the sink. This immediately cleans up the horrible mess in C of endless printf variants: fprintf, snprintf, vprintf, vfprintf, vsnprintf, ad nauseum. In fact, in D, we do have a separate .format() (.formattedWrite underneath) and .write. For convenience we have writef combine the two, but it's really no more than syntactic sugar. You could have just written: formattedWrite(stdout.lockingTextWriter, fmt, args...); The names could use some abbreviating, but the principle is sound.You can see this in the dmd implementation, where OutBuffer is the sink for formatted characters, and ErrorSink is used to accept messages about errors. By consolidating output into sinks, one does not have to check for an error at every invocation of printf.But that just returns you to the original problem: if the sink carries error information, someone needs to check it. If nobody does, then the code just barges along thinking everything is fine when the sink is already in an error state. No different from C programs ignoring the return code of printf and doing silly things when e.g. the disk is full. And as we all know, programmers are lazy; if error-checking is optional, nobody will do it. And enforcement doesn't work either: if you force people to handle error conditions, they will just do the bare minimum they can to get away with it. Hence the proliferation of C functions that return -1 (or equivalent dummy value) for any and every error condition, with no indication of what actually went wrong. Which leads to an entire application getting into an error state from some obscure combination of conditions, and the only message you can get out of it is "Internal error".I still use printf in dmd, but only for the porpoise of printing debugging information so I can debug the compiler. I use snprintf() for when things matter, because snprintf() accepts a (primitive) sink as an argument.(I'd love to be introduced to the porpoise that can help me debug compilers. But I digress. ;-) On a more serious note, I find D's .writefln a much better debugging tool than C's printf. Thanks to DbI, dumping the state of a complex type is often as simple as `writefln("%s", myBigStruct)`, as opposed to printf, where you have to manually spell out %-specifiers for every field of the struct you wish to examine. Combining writefln with UFCS chains makes it even more powerful: I often use it to debug code that handle multi-dimensional data; e.g., to dump 2D data stored in a 1D array, I can just write: ``` writefln("%-(%-(%s, %)\n%)", myFlatArray.chunks(myWidth)); ``` and instantly get nice output like this: ``` 1 2 3 4 5 6 7 8 9 ``` Try doing that in C, and you'll quickly find yourself spending an entire afternoon writing a debug module just to format debug info in a human-digestible way. In D, just a few seconds to write out the nested %-specifiers and you're on your way. T -- Obviously, some things aren't very obvious.
May 24
On 5/24/2026 5:47 PM, H. S. Teoh wrote:And enforcement doesn't work either: if you force people to handle error conditions, they will just do the bare minimum they can to get away with it. Hence the proliferation of C functions that return -1 (or equivalent dummy value) for any and every error condition, with no indication of what actually went wrong. Which leads to an entire application getting into an error state from some obscure combination of conditions, and the only message you can get out of it is "Internal error".You do have a point. However, it's much easier to put a single error check in the sink rather than in every single call to printf. (And this his how the sink works in dmd.) Keep in mind that the potential for an exception every single call will insert invisible unwinding code, which adds invisible complexity to your code. This is addressed in the referenced book.On a more serious note, I find D's .writefln a much better debugging tool than C's printf.You're right, but my issue with writefln is even a simple call to it generates and absolute blizzard of template code emitted to the object file. Since much of my work involves looking at the assembler dump of the code, it becomes hard to find what I'm looking for in that blizzard. I've discussed this with Adam (Phobos2) and he agrees and will address it.
May 24
On Sun, May 24, 2026 at 11:36:17PM -0700, Walter Bright via Digitalmars-d wrote:On 5/24/2026 5:47 PM, H. S. Teoh wrote:[...]The current implementation of writefln leaves a lot of room for improvement. A single call with a simple "%s" format pulls in the machinery for a truckload of specialized formatting code, like floating-point formatting (which like all things IEEE is exceedingly complex), BigInt handling, ad nauseum. Retrospect is always 20/20, as they say, but what *should* have been done is that the format string should be a compile-time argument that's scanned at compile-time by CTFE, and transformed into a series of straightforward calls for each argument. For example, writing: ``` writefln("Value at (%d, %d) is %.02f", x, y, price); ``` should generate the equivalent of: ``` writeln("Value at ("); writeln(formatInt(x)); writeln(", "); writeln(formatInt(y)); writeln(") is "); writeln(formatFloat(price); ``` I.e., it should only pull in what's actually used, not the entire formatting subsystem for handling every conceivable D type.On a more serious note, I find D's .writefln a much better debugging tool than C's printf.You're right, but my issue with writefln is even a simple call to it generates and absolute blizzard of template code emitted to the object file. Since much of my work involves looking at the assembler dump of the code, it becomes hard to find what I'm looking for in that blizzard.I've discussed this with Adam (Phobos2) and he agrees and will address it.Let's hope it will not be another over-engineered solution. T -- Every time you make a typo, the errorists win.
May 25
On 26/05/2026 2:29 AM, H. S. Teoh wrote:On Sun, May 24, 2026 at 11:36:17PM -0700, Walter Bright via Digitalmars-d wrote:There is a simple way to archive this, use IES. Give IES support for format strings, and a lot of these problems disappear. Not to mention we can kill off the entire f variants! But alas politics...On 5/24/2026 5:47 PM, H. S. Teoh wrote:[...]The current implementation of writefln leaves a lot of room for improvement. A single call with a simple "%s" format pulls in the machinery for a truckload of specialized formatting code, like floating-point formatting (which like all things IEEE is exceedingly complex), BigInt handling, ad nauseum. Retrospect is always 20/20, as they say, but what *should* have been done is that the format string should be a compile-time argument that's scanned at compile-time by CTFE, and transformed into a series of straightforward calls for each argument. For example, writing: ``` writefln("Value at (%d, %d) is %.02f", x, y, price); ``` should generate the equivalent of: ``` writeln("Value at ("); writeln(formatInt(x)); writeln(", "); writeln(formatInt(y)); writeln(") is "); writeln(formatFloat(price); ``` I.e., it should only pull in what's actually used, not the entire formatting subsystem for handling every conceivable D type.On a more serious note, I find D's .writefln a much better debugging tool than C's printf.You're right, but my issue with writefln is even a simple call to it generates and absolute blizzard of template code emitted to the object file. Since much of my work involves looking at the assembler dump of the code, it becomes hard to find what I'm looking for in that blizzard.I've discussed this with Adam (Phobos2) and he agrees and will address it.Let's hope it will not be another over-engineered solution.
May 25
On Tue, May 26, 2026 at 02:34:28AM +1200, Richard (Rikki) Andrew Cattermole via Digitalmars-d wrote:On 26/05/2026 2:29 AM, H. S. Teoh wrote:[...][...]The current implementation of writefln leaves a lot of room for improvement. A single call with a simple "%s" format pulls in the machinery for a truckload of specialized formatting code, like floating-point formatting (which like all things IEEE is exceedingly complex), BigInt handling, ad nauseum. Retrospect is always 20/20, as they say, but what *should* have been done is that the format string should be a compile-time argument that's scanned at compile-time by CTFE, and transformed into a series of straightforward calls for each argument. For example, writing:There is a simple way to archive this, use IES.What's IES? T -- If creativity is stifled by rigid discipline, then it is not true creativity.
May 25
On 26/05/2026 2:39 AM, H. S. Teoh wrote:On Tue, May 26, 2026 at 02:34:28AM +1200, Richard (Rikki) Andrew Cattermole via Digitalmars-d wrote:https://dlang.org/spec/istring.htmlOn 26/05/2026 2:29 AM, H. S. Teoh wrote:[...][...]The current implementation of writefln leaves a lot of room for improvement. A single call with a simple "%s" format pulls in the machinery for a truckload of specialized formatting code, like floating-point formatting (which like all things IEEE is exceedingly complex), BigInt handling, ad nauseum. Retrospect is always 20/20, as they say, but what *should* have been done is that the format string should be a compile-time argument that's scanned at compile-time by CTFE, and transformed into a series of straightforward calls for each argument. For example, writing:There is a simple way to archive this, use IES.What's IES? T
May 25
On Monday, 25 May 2026 at 14:34:28 UTC, Richard (Rikki) Andrew Cattermole wrote:There is a simple way to archive this, use IES. Give IES support for format strings, and a lot of these problems disappear. Not to mention we can kill off the entire f variants!100% That would be _awesome_ !!
May 25
On Sunday, 24 May 2026 at 01:42:43 UTC, Walter Bright wrote:The first sentence of the chapter "Define Errors Out Of Existence" says: "Exception handling is one of the worst sources of complexity in software systems." I suspect that adding EH to D was a mistake. It certainly was a mistake to build it into Unicode string handling. I'd like to see if we can figure a way to do Phobos without exception handling.Might find this interesting. https://rm4n0s.github.io/posts/3-error-handling-challenge/ Zz
May 24
On Sunday, 24 May 2026 at 17:15:12 UTC, Zz wrote:https://rm4n0s.github.io/posts/3-error-handling-challenge/ It's an error code but in a tagged union with N cases.The error to read a file in Odin: ```go Error :: union { General_Error, io.Error, runtime.Allocator_Error, sys_windows.System_Error, } ``` This has around 32 cases. I think the idea is fine sometimes, but ehh. Hard to tell what the error really is. Mostly an API issue in this case.
May 24
On 5/24/2026 11:02 AM, Kapendev wrote:The error to read a file in Odin:"OOOOdddiiiiinnnn!!!!" https://youtu.be/XMHts7ahWcY?t=153
May 24
On Sunday, 24 May 2026 at 17:15:12 UTC, Zz wrote:On Sunday, 24 May 2026 at 01:42:43 UTC, Walter Bright wrote:That's a good challenge, really. The problem I have with that however is very simple. Why the heck do you need a stack trace at runtime ? If you need a stack trace then it's probably cuz you have encountered a serious bug. Time to run the software in gdb you see.The first sentence of the chapter "Define Errors Out Of Existence" says: "Exception handling is one of the worst sources of complexity in software systems." I suspect that adding EH to D was a mistake. It certainly was a mistake to build it into Unicode string handling. I'd like to see if we can figure a way to do Phobos without exception handling.Might find this interesting. https://rm4n0s.github.io/posts/3-error-handling-challenge/ Zz
May 28
On Thu, May 28, 2026 at 08:50:57PM +0000, Basile B. via Digitalmars-d wrote:On Sunday, 24 May 2026 at 17:15:12 UTC, Zz wrote:[...][...] Running the program in gdb is a luxury you don't always have. I've had to fix segfault bugs that happen only in a customer's production environment, so (1) gdb access is not an option, not even remotely (this is running on embedded hardware); (2) the problem is not reproducible in my dev environment; (3) the customer is using a release build, so no symbols, only stack addresses and register contents at the time of the segfault; (4) the customer cannot run a custom debug build with debug hooks because this is a live production environment. Having a stack trace enabled me to trace the location of the crash (build the exact version the customer is running, map hex addresses to the disassembly of the executable in my build, trace through the assembly and map it back to the source code, then trace the code back up the chain of callers to determine where the bad value came from). Without that information, the bug would've remained open till this day. T -- There are two types of idiots. One type says "this is old and therefore bad", the other type says "this is new and therefore better". Beware of individuals who fall under both types. -- Crivenshttps://rm4n0s.github.io/posts/3-error-handling-challenge/ ZzThat's a good challenge, really. The problem I have with that however is very simple. Why the heck do you need a stack trace at runtime ? If you need a stack trace then it's probably cuz you have encountered a serious bug. Time to run the software in gdb you see.
May 28
AI elevates great architects but empowers unqualified users to fill codebases with toxic technical debt. From my experience, AI should never be let unsupervised. I seen that DMD started to merge Claude contributions, and that's a problem because most of them are merged by the same person who submitted them. D foundation should double the requirements needed to merge contributions made by AI, it should get at least 2 approvals from 2 different persons, and never be merged by the same person, they should also be properly tagged so they can be easily reviewed, after the fact, by anyone who wants to help. Contributors come and go, but the code they leave behind is permanent. If we care about the future of DMD, we cannot let short term AI convenience compromise long term codebase health. I have no desire reading Bun's codebase for example, because I know none of those concerns are valued, so why should I, the human, bother?
May 24
Do not get me wrong, I am pro AI, I advocate for automating software just like we are automating our factories, but the transition has to be handled with extra care!
May 24
On 5/24/2026 3:27 AM, libxmoc wrote:Do not get me wrong, I am pro AI, I advocate for automating software just like we are automating our factories, but the transition has to be handled with extra care!AI is just another tool.
May 24
On 5/24/2026 3:25 AM, libxmoc wrote:most of them are merged by the same person who submitted them.That's against our policy.
May 24
On Sunday, 24 May 2026 at 01:39:48 UTC, Walter Bright wrote:... I've not vibe coded enough to see it for myself, but I've been told that AI generated code simply generates code until it works. It doesn't do very well at managing complexity. Something to watch out for.I haven't vibe coding as well, but I have being using it to generate some code sql queries scripts or writing a better ones and it wasn't a pleasant experience. Where I work Devs are using it and some sql queries generated are pretty awful, making our Exadata suffering. Another thing, as DBA the other I asked the AI to generate a script to purge sql profiles or baselines from a given SQL_ID which is a very known script used for DBAs out there, the AI generate a script that would have clear this but for ALL queries on the Database, which could have be a huge mess. After telling the AI the script was wrong and it would have put my job at risk, the AI agreed, asked for excuses and generated a correct version later. xD Anyway I agree sometimes the AI can help a lot mainly for that dumb work, and it's nice for generating test cases too, but still It needed to be supervised. Matheus.
May 24
On 5/24/2026 5:08 AM, matheus wrote:Anyway I agree sometimes the AI can help a lot mainly for that dumb work, and it's nice for generating test cases too, but still It needed to be supervised.A wise decision. I wouldn't put my airplane on autopilot so I could go to the lav.
May 24
On Sunday, 24 May 2026 at 01:39:48 UTC, Walter Bright wrote:by John OusterhoutFor example, the title of Chapter 10 is "Define Errors out of Existence". I've been trying to do that since the 1980s.I haven't read that book, but Ousterhout has made the same point elsewhere for years, and I've never grasped the practical side of his argument. It would be nice to do, but it's a necessary part of a working program.I've not vibe coded enough to see it for myself, but I've been told that AI generated code simply generates code until it works. It doesn't do very well at managing complexity. Something to watch out for.There's a solution to this. I have the LLM program in a "new language" and upload the spec with some examples. No global state. A maximum of 60 lines in the body of a function. A maximum of 10 function arguments. No code blocks. Only goto for jumping around inside the function. You need to change the syntax to get it to accept that you have a new language, so I require line numbers at the start of every line. The problem with just telling the LLM to write a D program that does such and such without restrictions is that it wasn't trained to impose constraints like this to keep the complexity under control, and there's no way it can work well with the amount of context that's required to write a program that can easily be modified in the future.
May 24
On 5/24/2026 6:13 AM, Lance Bachmeier wrote:I haven't read that book, but Ousterhout has made the same point elsewhere for years, and I've never grasped the practical side of his argument. It would be nice to do, but it's a necessary part of a working program.You are correct that it is not necessary. However, I recognize a number of complexity-reducing techniques I use that are in the book.There's a solution to this. I have the LLM program in a "new language" and upload the spec with some examples. No global state. A maximum of 60 lines in the body of a function. A maximum of 10 function arguments. No code blocks. Only goto for jumping around inside the function. You need to change the syntax to get it to accept that you have a new language, so I require line numbers at the start of every line. The problem with just telling the LLM to write a D program that does such and such without restrictions is that it wasn't trained to impose constraints like this to keep the complexity under control, and there's no way it can work well with the amount of context that's required to write a program that can easily be modified in the future.I agree with no global state, however, the 60 line limit is arbitrary. Complexity comes from how much state you need to keep in your head, not how many lines of code.
May 24
On Monday, 25 May 2026 at 05:55:59 UTC, Walter Bright wrote:The limit of 60 lines is for the LLM. It hadn't even entered my mind, but was proposed by Gemini. It allows a proper balance between being long enough to incorporate the needed functionality while keeping the necessary context low enough that the output is highly likely to be correct.There's a solution to this. I have the LLM program in a "new language" and upload the spec with some examples. No global state. A maximum of 60 lines in the body of a function. A maximum of 10 function arguments. No code blocks. Only goto for jumping around inside the function. You need to change the syntax to get it to accept that you have a new language, so I require line numbers at the start of every line. The problem with just telling the LLM to write a D program that does such and such without restrictions is that it wasn't trained to impose constraints like this to keep the complexity under control, and there's no way it can work well with the amount of context that's required to write a program that can easily be modified in the future.I agree with no global state, however, the 60 line limit is arbitrary. Complexity comes from how much state you need to keep in your head, not how many lines of code.
May 25
On 5/25/2026 8:02 AM, Lance Bachmeier wrote:The limit of 60 lines is for the LLM. It hadn't even entered my mind, but was proposed by Gemini. It allows a proper balance between being long enough to incorporate the needed functionality while keeping the necessary context low enough that the output is highly likely to be correct.This is conventional wisdom, but the book argues against it, based in the idea that two functions that are strongly connected are not really an improvement.
May 25
On Sunday, 24 May 2026 at 01:39:48 UTC, Walter Bright wrote:by John Ousterhout https://www.amazon.com/Philosophy-Software-Design-2nd/dp/173210221XThis book is what quite few well-known AI gurus mentioned lately in their podcasts lately. No wonder why. :D
May 24
On 5/24/2026 2:19 PM, Dejan Lekic wrote:This book is what quite few well-known AI gurus mentioned lately in their podcasts lately. No wonder why. :DThat's how I found out about it!
May 24
On Sunday, 24 May 2026 at 01:39:48 UTC, Walter Bright wrote:My compiler took a different approach. It would just keep enlarging the string buffer until it ran out of memory. Then there was only one error message - "out of memory" - and the compiler would abort. This applied to all sorts of arbitrary limits the C spec placed on things. There was no need to add error recovery code.I dunno, I don't really agree with this point of view. If your software isn't doing proper error handling, then I don't think you're really writing serious software; you're doing toy hobby projects. It'd drive me insane trying to use a compiler that randomly dies in the middle of compilation with only an "out of memory" message to tell me what went wrong. Imagine if all software were written this way - it'd be complete and utter hell. That exception handling quote from the book seems ridiculous to me as well. I worked in cybersecurity for over 10 years on multi-million LoC SIEM products, huge multi-team, cloud-based, microservice architecture products, enterprise server software... exception handling was never a major source of complexity in any of them. The three major sources of complexity were: 1. The business logic of the applications. 2. Ensuring the various components were initialized properly, atomically, and in the correct order. 3. The enormous tech debt that comes from people doing ugly hacks to get something implemented as quickly as possible, which years down the line become essentially impossible to remove without rewriting huge swathes of code.
May 24
On 5/24/2026 11:15 PM, Meta wrote:I dunno, I don't really agree with this point of view. If your software isn't doing proper error handling, then I don't think you're really writing serious software; you're doing toy hobby projects. It'd drive me insane trying to use a compiler that randomly dies in the middle of compilation with only an "out of memory" message to tell me what went wrong. Imagine if all software were written this way - it'd be complete and utter hell.I never saw it fail in practice. You'd have to write a string that was more than 64Kb in size (for the PC) and more than a gigabyte (for modern computers). I don't think that sort of code would be harboring such a string without the programmer knowing about it.That exception handling quote from the book seems ridiculous to me as well. I worked in cybersecurity for over 10 years on multi-million LoC SIEM products, huge multi-team, cloud-based, microservice architecture products, enterprise server software... exception handling was never a major source of complexity in any of them.As I am unfamiliar with your code, I can't have an opinion on it!The three major sources of complexity were: 1. The business logic of the applications. 2. Ensuring the various components were initialized properly, atomically, and in the correct order. 3. The enormous tech debt that comes from people doing ugly hacks to get something implemented as quickly as possible, which years down the line become essentially impossible to remove without rewriting huge swathes of code.Yes, of course!
May 25
I forgot to mention - an out of memory error is nearly always a fatal error for
a program. There's no reason one couldn't, when failing to enlarge the string
buffer:
```
char* buffer = cast(char*)malloc(newsize);
if (!buffer)
fatal_error("string too big for memory!");
```
And another problem with exceptions are the "double fault" ones, where an
exception is thrown from within an exception. That's a fatal error.
May 25
On Monday, 25 May 2026 at 17:26:59 UTC, Walter Bright wrote:I forgot to mention - an out of memory error is nearly always a fatal error for a program. There's no reason one couldn't, when failing to enlarge the string buffer: ``` char* buffer = cast(char*)malloc(newsize); if (!buffer) fatal_error("string too big for memory!"); ```Ah yes, okay, that's at least better than a cryptic "out of memory" error.And another problem with exceptions are the "double fault" ones, where an exception is thrown from within an exception. That's a fatal error.True, although most software I've worked on was written almost entirely in Java, with supplementary pieces on Python, Perl, Go, Lua, Bash, etc. I think these type of "double fault" exceptions are mostly a problem in C++, because the way it does exceptions is so convoluted. Most "managed" languages do it differently, and IMO better. Java for example uses a similar "chaining" mechanism to D, which I've used heavily in a lot of code I've written.
May 25
On Monday, 25 May 2026 at 16:41:35 UTC, Walter Bright wrote:On 5/24/2026 11:15 PM, Meta wrote:Okay, fair enough. I can't ever recall seeing strings that large in source code, so it's probably not a case that you'd ever have to worry about, realistically. Still, wouldn't it be better to fail compilation with a "string too long" error message instead of "out of memory"? It's those weird, very niche corner cases where you most want descriptive error messages.I dunno, I don't really agree with this point of view. If your software isn't doing proper error handling, then I don't think you're really writing serious software; you're doing toy hobby projects. It'd drive me insane trying to use a compiler that randomly dies in the middle of compilation with only an "out of memory" message to tell me what went wrong. Imagine if all software were written this way - it'd be complete and utter hell.I never saw it fail in practice. You'd have to write a string that was more than 64Kb in size (for the PC) and more than a gigabyte (for modern computers). I don't think that sort of code would be harboring such a string without the programmer knowing about it.
May 25
About error handling: (1) handling all errors increases code complexity; (2) not all errors which *can* occur *will* occur for the specific states in your program; and (3) not all errors are recoverable in practice, even if they could be in theory. I understand that exception handling might be considered "complex" from the compiler-writer's perspective, but from the perspective of application logic that simply is not true. Replacing exception handling with some other mechanism does not magically make the issue of stack unwinding go away. You simply have to do it manually instead, and often for conditions that you don't care about. A far more serious and concerning source of complexity is retrofitting overly ambitious features onto a design that was never intended for them. Indraj
May 25
On Mon, May 25, 2026 at 09:36:03AM +0100, Indraj Gandham via Digitalmars-d wrote: [...]A far more serious and concerning source of complexity is retrofitting overly ambitious features onto a design that was never intended for them.[...] And having to do this by an unreasonably short deadline because some high-paying customer demands for it to have been done by yesterday, resulting in hasty one-time hacks that break good coding practices and accumulate over time to be a huge technical debt that takes years of effort down the road to fix. T -- The past, present, and future walk into a bar. It was tense. Then the physicist walks in, and it was tensor. Finally, the mathematician walks in, and it was ten sets.
May 25
On Sunday, 24 May 2026 at 01:39:48 UTC, Walter Bright wrote:I've not vibe coded enough to see it for myself, but I've been told that AI generated code simply generates code until it works. It doesn't do very well at managing complexity. Something to watch out for.My own understanding of it at the moment is that there are many shades of "vibey" AI usage: - Code reviews: useful and often find small things, it kinda replaces linters and static analysis. Arguably LLMs are better at reading than writing. Bug finding can feel fresh if you already know it's an uninteresting bug. - Constrained design: "do X using Y method". You tend to keep ownership and control of the design. Though the LLM may have to work more because of the constraints (such as : "use this language"). - Full vibecoding is the most strange, you tend to get a usable output though with objectionnable architecture and "debt". In this mode you don't even look at the code. At times, the LLM will suggest astoundingly bad ideas but mostly it will be quite good. Better when the LLM can assess results itself, lest it's bottleneck by doing QA and visual inspection. Essentially feels like product design and quality assurance. The bad side is that you get 0 ownership feel and no confidence it works beyond the tested cases. The tools are made more dangerous because they encourage to not look at the code, and in organizations you can read a lot of horror stories.
May 25









Walter Bright <newshound2 digitalmars.com> 