Re: C-like static array size inference - how?
On Tuesday, 7 June 2022 at 00:20:31 UTC, Ali Çehreli wrote: On 6/6/22 17:04, arandomonlooker wrote: > [...] syntax causes > [...] As you already know, the correct syntax is 'int[]' :) but it won't work because -betterC cannot support dynamic array. [...] Thank you. I was kind of distracted and i didn't type it correctly. Your solution works.
Re: want to confirm: gc will not free a non-gc-allocated field of a gc-allocated object?
On Tuesday, 7 June 2022 at 00:40:56 UTC, ag0aep6g wrote: On 07.06.22 00:22, max haughton wrote: float[] doesn't contain pointers, so the GC won't do anything to or with it. wat float[] is a pointer (plus a length). The GC will deal with it like any other pointer. I'm talking about the data in the array. void[] might contain pointers, float[] does not so it won't be scanned. Or at least shouldn't be... This is why you shouldn't use void[] for everything if you can help it. ``` void main() { import std.stdio; auto voidArray = typeid(void[]); auto floatArray = typeid(float[]); writeln(voidArray.next.flags() & 1 ); writeln(floatArray.next.flags() & 1); } ```
Re: want to confirm: gc will not free a non-gc-allocated field of a gc-allocated object?
On 07.06.22 00:22, max haughton wrote: float[] doesn't contain pointers, so the GC won't do anything to or with it. wat float[] is a pointer (plus a length). The GC will deal with it like any other pointer.
Re: C-like static array size inference - how?
On 6/6/22 17:04, arandomonlooker wrote: > I usually transcribe them as follows, because the previous syntax causes > a compiler error: > > ```d > int numbersINeed[] = [1, 2, 3, 4, 5]; > ``` As you already know, the correct syntax is 'int[]' :) but it won't work because -betterC cannot support dynamic array. > it's complaining about TypeInfo being absent. What an unfortunate error message! Trying writeln() causes equally weird error messages. > Can't i use some feature to imply that D must deduct the size > from the array i am assigning, like an underscore? Can't D do that? That request comes up relatively frequently. Currently, the only way I know of is to use std.array.staticArray: import std.array; extern (C) void main() { auto numbersINeed = staticArray([1, 2, 3, 4, 5]); import std.range; import std.algorithm; import core.stdc.stdio; // | // V numbersINeed[].each!(n => printf("%d ", n)); } Aside: I printed the elements with a range algorithm, which is not necessary at all. However, the reason I had to use it is because static arrays are not ranges because their lengths cannot change. [] takes a slice to all elements, which can reduce its length, and accordingly is a range. Ali
C-like static array size inference - how?
Hello. I am working on a project related to low-level development as a beginner, and i decided to pick D as the most optimal programming language for that, in large part because of it's strong integration with C and C++. I happen to have a lot of arrays that i want to translate to D, formulated as follows (it's a unrelated example): ```c int numbersINeed[] = {1, 2, 3, 4, 5}; ``` I usually transcribe them as follows, because the previous syntax causes a compiler error: ```d int numbersINeed[] = [1, 2, 3, 4, 5]; ``` As i'm using the betterC mode, it's complaining about TypeInfo being absent. Can't i use some feature to imply that D must deduct the size from the array i am assigning, like an underscore? Can't D do that? Thanks in advance to you all.
Re: Copy Constructor
On Sunday, 5 June 2022 at 15:45:17 UTC, Salih Dincer wrote: Also, when we write to the screen with writeln(), why four times copy-constructors are running? **Playground:** https://run.dlang.io/is/qHvLJe I solved the problem by implementing the `toString()` member function. I also had to use a helper `writeout()` as below: **struct Foo {** ```d string toString() { return format("%s", payload); } ``` **void main() {** ```d void writeout(T)(T text) { text.toString.writeln;/* import std.conv; text.to!string.writeln;//*/ } writeout(three); ``` Interestingly, even using `to!string` the copy-constructor works extra +4 times! I think there will be performance losses if `write()` is used unconsciously everywhere! Although this way, it kisses with ctor +1 times :) SDB@79
Re: want to confirm: gc will not free a non-gc-allocated field of a gc-allocated object?
On Mon, Jun 06, 2022 at 10:18:08PM +, mw via Digitalmars-d-learn wrote: > Hi, > > Suppose I have this code: > > ``` > class GCAllocated { > float[] data; > > this() { > // non-gc-allocated field > this.data = cast(float[])(core.stdc.stdlib.malloc(nBytes)[0 .. nBytes]); > } > } > > void foo() { > auto obj = new GCAllocated(); // gc-allocated owning object > ... > } > > ``` > > So when `obj` is cleanup by the GC, obj.data won't be freed by the GC: > because the `data` is non-gc-allocated (and it's allocated on the > non-gc heap), the GC scanner will just skip that field during a > collection scan. Is this understanding correct? > > I need this behavior for a special purpose, so I want to confirm it. [...] Short answer: yes, the GC will not do anything with that field. Long answer: even if the GC wanted to do something about that field, how could it? It has no information about how it was allocated. As far as the GC is concerned, it's just a pointer + size pair, just like any other array, and the pointer happens to point outside of GC-allocated memory. Beyond that, the GC knows nothing else about the pointer. Is it allocated by malloc? Is it pointing to static memory? Is it some user-defined custom allocator? Is it some random garbage value? Who knows. The GC knows nothing about the pointer, so it conservatively ignores it. On a more general implementational note, D's GC is conservative, meaning that if an aligned pointer-sized value looks like it might be a pointer value, the GC will assume, erring on the side of being overly cautious, that it *is* a pointer value, and mark any GC memory that it might happen to point to as live. The value could be an int or long, and the GC wouldn't know any better. (More recent precise implementations may skip some of these false positives, though.) The same principle applies, though: if the pointer has a value that the GC doesn't know about (i.e., doesn't point to any of the known GC blocks) then the GC will conservatively just ignore it. T -- Give a man a fish, and he eats once. Teach a man to fish, and he will sit forever.
Re: want to confirm: gc will not free a non-gc-allocated field of a gc-allocated object?
On Monday, 6 June 2022 at 22:24:45 UTC, Guillaume Piolat wrote: My understanding is that while scanning, the GC will see the data.ptr pointer, but will not scan the area it points to since it's not in a GC range (the runtime can distinguish managed pointer and other pointers). After scanning, when obj is non-reachable, the GC will destroy it but that won't lead to a reclaim of data.ptr since it knows it doesn't own that. In D, the ownership of slice is purely determined by the memory area it points to. If it points into GC memory then it's a GC slice.
Re: want to confirm: gc will not free a non-gc-allocated field of a gc-allocated object?
On Monday, 6 June 2022 at 22:22:05 UTC, max haughton wrote: float[] doesn't contain pointers, so the GC won't do anything to or with it. does every array have a .ptr attr? https://dlang.org/spec/arrays.html Dynamic Array Properties .ptrReturns a pointer to the first element of the array.
Re: want to confirm: gc will not free a non-gc-allocated field of a gc-allocated object?
On Monday, 6 June 2022 at 22:18:08 UTC, mw wrote: So when `obj` is cleanup by the GC, obj.data won't be freed by the GC: because the `data` is non-gc-allocated (and it's allocated on the non-gc heap), the GC scanner will just skip that field during a collection scan. Is this understanding correct? My understanding is that while scanning, the GC will see the data.ptr pointer, but will not scan the area it points to since it's not in a GC range (the runtime can distinguish managed pointer and other pointers). After scanning, when obj is non-reachable, the GC will destroy it but that won't lead to a reclaim of data.ptr since it knows it doesn't own that.
Re: want to confirm: gc will not free a non-gc-allocated field of a gc-allocated object?
On Monday, 6 June 2022 at 22:18:08 UTC, mw wrote: Hi, Suppose I have this code: ``` class GCAllocated { float[] data; this() { // non-gc-allocated field this.data = cast(float[])(core.stdc.stdlib.malloc(nBytes)[0 .. nBytes]); } } void foo() { auto obj = new GCAllocated(); // gc-allocated owning object ... } ``` So when `obj` is cleanup by the GC, obj.data won't be freed by the GC: because the `data` is non-gc-allocated (and it's allocated on the non-gc heap), the GC scanner will just skip that field during a collection scan. Is this understanding correct? I need this behavior for a special purpose, so I want to confirm it. Thanks. float[] doesn't contain pointers, so the GC won't do anything to or with it.
want to confirm: gc will not free a non-gc-allocated field of a gc-allocated object?
Hi, Suppose I have this code: ``` class GCAllocated { float[] data; this() { // non-gc-allocated field this.data = cast(float[])(core.stdc.stdlib.malloc(nBytes)[0 .. nBytes]); } } void foo() { auto obj = new GCAllocated(); // gc-allocated owning object ... } ``` So when `obj` is cleanup by the GC, obj.data won't be freed by the GC: because the `data` is non-gc-allocated (and it's allocated on the non-gc heap), the GC scanner will just skip that field during a collection scan. Is this understanding correct? I need this behavior for a special purpose, so I want to confirm it. Thanks.
Re: What happened to Circular Studio?
On 6/6/22 3:46 PM, Jack wrote: I just found out a game using D to develop games but later I see the last updates on the github, web site, twitter etc is from 2015. Does anyone knows what happend to the company? It appears to be just a playground for a bunch of friends at RIT, I'm not sure how much of a "company" this was. But, there is activity in the github issues list, circa November 2020: https://github.com/Circular-Studios/Dash/issues/249 But who knows, probably just fizzled out. I admit, I never heard of them. -Steve
Re: What happened to Circular Studio?
for those that don't know: https://circularstudios.com/
What happened to Circular Studio?
I just found out a game using D to develop games but later I see the last updates on the github, web site, twitter etc is from 2015. Does anyone knows what happend to the company?
Re: How to map machine instctions in memory and execute them? (Aka, how to create a loader)
On Monday, 6 June 2022 at 18:05:23 UTC, Johan wrote: This instruction is wrong. Note that you are writing twice to RDX, but also that you are using `mov sign_extend imm32, reg64` instead of `mov imm64, reg64` (`0x48 0xBA`?). Third, why append an extra zero (`*cast(char*)(code + 32) = 0x00;`)? That must be a bug too. cheers, Johan Thanks! It seems that there is probably a "typo" from the original [source](https://github.com/vishen/go-x64-executable) that I got the code. The hex values are different however so there is only a mistake in the comment, the code normally works in the example repository (and I made a D version that works too). The padding in the end seems to be necessary else the example doesn't compile (I don't know why, I'm SUPER n00b when it comes to machine language, I don't know almost anything!). I'm also not sure how the "encode" will be for `mov imm64, reg64` as I tried to type what you typed in the parenthesis and it doesn't seem to work.
Re: Comparing Exceptions and Errors
On Monday, 6 June 2022 at 18:08:17 UTC, Ola Fosheim Grøstad wrote: There is no reason for D to undercut users of @safe code. (Wrong usage of the term «undercut», but you get the idea…)
Re: Comparing Exceptions and Errors
On Monday, 6 June 2022 at 17:52:12 UTC, Steven Schveighoffer wrote: Then that's part of the algorithm. You can use an Exception, and then handle the exception by calling the real sort. If in the future, you decide that it can properly sort with that improvement, you remove the Exception. That is different from e.g. using a proven algorithm, like quicksort, but failing to implement it properly. No? Why do you find it so? Adding a buggy optimization is exactly failing to implement it properly. There is a reference, the optimization should work exactly like the reference, but didn't. Using asserts in @safe code should be no different than using asserts in Python code. Python code <=> safe D code. Python library implemented in C <=> trusted D code. There is no reason for D to undercut users of @safe code. If anything D should try to use @safe to provide benefits that C++ users don't get.
Re: How to map machine instctions in memory and execute them? (Aka, how to create a loader)
On Monday, 6 June 2022 at 15:13:45 UTC, rempas wrote: ``` // mov rdx, *cast(char*)(code + 14) = 0x48; *cast(char*)(code + 15) = 0xC7; *cast(char*)(code + 16) = 0xC2; *cast(char*)(code + 17) = 12; *cast(char*)(code + 18) = 0x00; *cast(char*)(code + 19) = 0x00; *cast(char*)(code + 20) = 0x00; // mov rdx, *cast(char*)(code + 21) = 0x48; *cast(char*)(code + 22) = 0xC7; *cast(char*)(code + 23) = 0xC1; *cast(long*)(code + 24) = cast(long)data; *cast(char*)(code + 32) = 0x00; ``` This instruction is wrong. Note that you are writing twice to RDX, but also that you are using `mov sign_extend imm32, reg64` instead of `mov imm64, reg64` (`0x48 0xBA`?). Third, why append an extra zero (`*cast(char*)(code + 32) = 0x00;`)? That must be a bug too. cheers, Johan
Re: Comparing Exceptions and Errors
On 6/6/22 12:15 PM, Ola Fosheim Grøstad wrote: On Monday, 6 June 2022 at 15:54:16 UTC, Steven Schveighoffer wrote: If it's an expected part of the sorting algorithm that it *may fail to sort*, then that's not an Error, that's an Exception. No, it is not expected. Let me rewrite my answer to Sebastiaan to fit with the sort scenario: For instance, you may have a formally verified sort function, but it is too slow. So you optimize one selected bottle neck, but that cannot be verified, because verification is hard. That specific unverified softspot is guarded by an assert. The compiler may remove it or not. Your shipped product fails, because the hard to read optimization wasn't perfect. So you trap the thrown assert and call the reference implementation instead. The cool thing with actors/tasks is that you can make them as small and targeted and revert to fallbacks if they fail. (Assuming 100% @safe code.) Then that's part of the algorithm. You can use an Exception, and then handle the exception by calling the real sort. If in the future, you decide that it can properly sort with that improvement, you remove the Exception. That is different from e.g. using a proven algorithm, like quicksort, but failing to implement it properly. -Steve
Re: Comparing Exceptions and Errors
On Monday, 6 June 2022 at 16:15:19 UTC, Ola Fosheim Grøstad wrote: On Monday, 6 June 2022 at 15:54:16 UTC, Steven Schveighoffer wrote: If it's an expected part of the sorting algorithm that it *may fail to sort*, then that's not an Error, that's an Exception. No, it is not expected. Let me rewrite my answer to Sebastiaan to fit with the sort scenario: Let me sketch up another scenario. Let's say I am making an online game and I need early feedback from beta-testers. So I run my beta-service with lots of asserts and logging, when actors fail I discard them and relaunch them. If the server went down on the first assert I wouldn't be able to test my server at all, because there would be no users willing to participate in a betatest where the server goes down every 20 seconds! That is a very bad high risk-factor, that totally dominates this use scenario. An engineer has to fill words such as «reliability», «utility», «probability» and «risk» with meaning that match the use scenario and make deliberate choices (cost-benefit-risk considerations). That includes choosing an actor model, and each actor has to prevent failure from affecting other actors. (by definition of «actor»).
Re: How to map machine instctions in memory and execute them? (Aka, how to create a loader)
On Monday, 6 June 2022 at 16:24:58 UTC, Guillaume Piolat wrote: See: https://github.com/GhostRain0/xbyak https://github.com/MrSmith33/vox/blob/master/source/vox/utils/mem.d Thank you! And I just noticed that the second source is from Vox
Re: How to map machine instctions in memory and execute them? (Aka, how to create a loader)
On Monday, 6 June 2022 at 16:08:28 UTC, Adam D Ruppe wrote: On a lot of systems, it can't be executable and writable at the same time, it is a security measure. see https://en.wikipedia.org/wiki/W%5EX so you might have to mprotect it to remove the write permission before trying to execute it. idk though Thank you! This was very helpful and I can see why it is a clever idea to not allow it (and I love that OpenBSD was the first introducing it!!) and I love security stuff ;) However, even with "mprotect" or If I just use "PROT_READ" and "PROT_EXEC", it still doesn't work so there should be something else I'm doing wrong...
Re: How to map machine instctions in memory and execute them? (Aka, how to create a loader)
On Monday, 6 June 2022 at 15:13:45 UTC, rempas wrote: Any ideas? See: https://github.com/GhostRain0/xbyak https://github.com/MrSmith33/vox/blob/master/source/vox/utils/mem.d
Re: Comparing Exceptions and Errors
On Monday, 6 June 2022 at 15:54:16 UTC, Steven Schveighoffer wrote: If it's an expected part of the sorting algorithm that it *may fail to sort*, then that's not an Error, that's an Exception. No, it is not expected. Let me rewrite my answer to Sebastiaan to fit with the sort scenario: For instance, you may have a formally verified sort function, but it is too slow. So you optimize one selected bottle neck, but that cannot be verified, because verification is hard. That specific unverified softspot is guarded by an assert. The compiler may remove it or not. Your shipped product fails, because the hard to read optimization wasn't perfect. So you trap the thrown assert and call the reference implementation instead. The cool thing with actors/tasks is that you can make them as small and targeted and revert to fallbacks if they fail. (Assuming 100% @safe code.) It says that the programmer cannot attribute exactly where this went wrong because otherwise, he would have accounted for it, or thrown an Exception instead (or some other mitigation). He can make a judgement. If this happened in a safe pure function then it would most likely be the result of what is what meant to do: check that the assumptions of the algorithm holds. Anything from memory corruption, to faulty hardware, to bugs in the code, could be the cause. That is not what asserts check! They will be removed if the static analyzer is powerful enough. All the information to remove the assert should be in the source code. You are asserting that *given all the constraints of the type system* then the assert should hold. Memory corruption could make an assert succeed when it should not, because then anything can happen! It cannot catch memory corruption reliably because it is not excluded from optimization. You need something else for that, something that turns off optimization for all asserts. Exactly. Use Exceptions if it's recoverable, Errors if it's not. This is what is not true, asserts says only something about the algorithm it is embedded in, it says that the algorithm makes a wrong assumption, and that is all. It says nothing about the calling environment. A failed assert could be because of undefined behavior. It doesn't *imply* it, but it cannot be ruled out. And a successful assert could happen because of undefined behaviour or optimization! If you want these types of guards then you need to propose a type of asserts that would be excluded from optimization. (which might be a good idea!) In the case of UB anything can happen. It is up to the programmer to make that judgment based on the use scenario. It is a matter of probabilisitic calculations in relation to the use scenario of the application. As I pointed out elsewhere: «reliability» has to be defined in terms of the use scenario by a skilled human being, not in terms of some kind of abstract thinking about compiler design.
Re: How to map machine instctions in memory and execute them? (Aka, how to create a loader)
On Monday, 6 June 2022 at 15:13:45 UTC, rempas wrote: void* code = mmap(null, cast(ulong)500, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0); On a lot of systems, it can't be executable and writable at the same time, it is a security measure. see https://en.wikipedia.org/wiki/W%5EX so you might have to mprotect it to remove the write permission before trying to execute it. idk though
Re: How to map machine instctions in memory and execute them? (Aka, how to create a loader)
On Monday, 6 June 2022 at 15:27:12 UTC, Alain De Vos wrote: Note , it is also possible to do inline assembly with asm{...} or __asm(T) {..}. Thank you for the info! I am aware of that, I don't want to practically do this. I just want to learn how it works. It will be useful when I'll built my own OS.
Re: Comparing Exceptions and Errors
On 6/6/22 12:59 AM, Ola Fosheim Grøstad wrote: On Sunday, 5 June 2022 at 23:57:19 UTC, Steven Schveighoffer wrote: It basically says "If this condition is false, this entire program is invalid, and I don't know how to continue from here." No, it says: this function failed to uphold this invariant. You can perfectly well recover if you know what that function touches. For instance if a sort function fails, then you can call a slower sort function. If it's an expected part of the sorting algorithm that it *may fail to sort*, then that's not an Error, that's an Exception. Or in terms of actors/tasks: if one actor-solver fails numerically, then you can recover and use a different actor-solver. If the condition is recoverable => Exception. If it is not recoverable => Error. An assert says nothing about the whole program. An assert says that something is wrong, and this was not expected or foreseen. It says that the programmer cannot attribute exactly where this went wrong because otherwise, he would have accounted for it, or thrown an Exception instead (or some other mitigation). Anything from memory corruption, to faulty hardware, to bugs in the code, could be the cause. An assert only says that the logic of that particular function is not meeting the SPEC. That's one possible reason. But if you are *planning* on possibly not meeting the spec (such as your sort example), that is a different story. Only the programmer knows if recovery is possible, not the compiler. Exactly. Use Exceptions if it's recoverable, Errors if it's not. A failed assert is not implying undefined behaviour in @safe code. A failed assert could be because of undefined behavior. It doesn't *imply* it, but it cannot be ruled out. -Steve
Re: How to map machine instctions in memory and execute them? (Aka, how to create a loader)
Note , it is also possible to do inline assembly with asm{...} or __asm(T) {..}.
How to map machine instctions in memory and execute them? (Aka, how to create a loader)
I tried to find anything that will show code but I wasn't able to find anything expect for an answer on stackoverflow. I would find a lot of theory but no practical code that works. What I want to do is allocate memory (with execution mapping), add the machine instructions and then allocate another memory block for the data and finally, execute the block of memory that contains the code. So something like what the OS loader does when reading an executable. I have come with the following code: ```d import core.stdc.stdio; import core.stdc.string; import core.stdc.stdlib; import core.sys.linux.sys.mman; extern (C) void main() { char* data = cast(char*)mmap(null, cast(ulong)15, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); memset(data, 0x0, 15); // Default value *data = 'H'; data[1] = 'e'; data[2] = 'l'; data[3] = 'l'; data[4] = 'o'; data[5] = ' '; data[6] = 'w'; data[7] = 'o'; data[8] = 'r'; data[9] = 'l'; data[10] = 'd'; data[11] = '!'; void* code = mmap(null, cast(ulong)500, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0); memset(code, 0xc3, 500); // Default value /* Call the "write" and "exit" system calls*/ // mov rax, 0x04 *cast(char*)code = 0x48; *cast(char*)(code + 1) = 0xC7; *cast(char*)(code + 2) = 0xC0; *cast(char*)(code + 3) = 0x04; *cast(char*)(code + 4) = 0x00; *cast(char*)(code + 5) = 0x00; *cast(char*)(code + 6) = 0x00; // mov rbx, 0x01 *cast(char*)(code + 7) = 0x48; *cast(char*)(code + 8) = 0xC7; *cast(char*)(code + 9) = 0xC3; *cast(char*)(code + 10) = 0x01; *cast(char*)(code + 11) = 0x00; *cast(char*)(code + 12) = 0x00; *cast(char*)(code + 13) = 0x00; // mov rdx, *cast(char*)(code + 14) = 0x48; *cast(char*)(code + 15) = 0xC7; *cast(char*)(code + 16) = 0xC2; *cast(char*)(code + 17) = 12; *cast(char*)(code + 18) = 0x00; *cast(char*)(code + 19) = 0x00; *cast(char*)(code + 20) = 0x00; // mov rdx, *cast(char*)(code + 21) = 0x48; *cast(char*)(code + 22) = 0xC7; *cast(char*)(code + 23) = 0xC1; *cast(long*)(code + 24) = cast(long)data; *cast(char*)(code + 32) = 0x00; // int 0x80 *cast(char*)(code + 33) = 0xcd; *cast(char*)(code + 34) = 0x80; /* Execute the code */ (cast(void* function()))(); } ``` I'm 100% sure that the instructions work as I have tested them with another example that creates an ELF executable file and it was able to execute correctly. So unless I copy-pasted them wrong, the instructions are not the problem. The only thing that may be wrong is when I'm getting the location of the "data" "segment". In my eyes, this uses 8 bytes for the memory address (I'm in a 64bit machine) and it takes the memory address the "data" variable holds so I would expect it to work Any ideas?
Re: Comparing Exceptions and Errors
On Monday, 6 June 2022 at 06:56:46 UTC, Ola Fosheim Grøstad wrote: On Monday, 6 June 2022 at 06:14:59 UTC, Sebastiaan Koppe wrote: Those are not places where you would put an assert. The only place to put an assert is when *you* know there is no recovery. No, asserts are orthogonal to recovery. They just specify the assumed constraints in the implementation of the algorithm. You can view them as comments that can be read by a computer and checked for that specific function. I guess an informal way to express this is: *Asserts are comments that you would need to make when explaining why the algorithm works to another person (or to convince yourself that it works).* As far as unnecessary asserts, it would be nice to have something more powerful than static assert, something that could reason about runtime issues that are simple and issue errors if it could not establish it. E.g.: ``` int i = 0; …later… i++; …much later… compiletime_assert(i>0); ```
Re: Copy Constructor
On 6/5/22 14:57, Ali Çehreli wrote: > struct Foo { >Foo dup() { > auto result = Foo(this.payload); > // ... > return result; >} > } > > In that case, the "named return value optimization" (NRVO) would be > applied and the object would still be moved to 'x'. I am wrong there as well: Technically, NRVO (or RVO) does not move but constructs the object in the caller's stack frame. So, if the caller has the following code: auto z = existing.dup(); Then 'result' inside dup() is the same as caller's 'z'. Not 'result' but 'z' would be constructed in dup(). No move is performed and no value is actually returned. Ali
Re: Comparing Exceptions and Errors
On Monday, 6 June 2022 at 06:14:59 UTC, Sebastiaan Koppe wrote: Those are not places where you would put an assert. The only place to put an assert is when *you* know there is no recovery. No, asserts are orthogonal to recovery. They just specify the assumed constraints in the implementation of the algorithm. You can view them as comments that can be read by a computer and checked for that specific function. For instance you can have a formally proven reference implementation full of asserts, then one optimized version where you keep critical asserts or just the post condition. If the optimized version fails, then you can revert to the reference (with no or few asserts, because it is already formally verified). There is nothing wrong with having many asserts or asserts you «know» to hold. They are helpful when you modify code and datastructures. Maybe one could have more selective ways to leave out asserts (e.g. based on revision) so that you remove most asserts in actors that has not changed since version 1.0 and retain more asserts in new actors. Also, if you fully check the full post condition (in @safe code) then you can remove all asserts in release as they are inconsequential. So the picture is more nuanced and it should be up to the programmer to decide, but maybe a more expressive and selective regime is useful.
Re: Comparing Exceptions and Errors
On Monday, 6 June 2022 at 04:59:05 UTC, Ola Fosheim Grøstad wrote: For instance if a sort function fails, then you can call a slower sort function. Or in terms of actors/tasks: if one actor-solver fails numerically, then you can recover and use a different actor-solver. Those are not places where you would put an assert. The only place to put an assert is when *you* know there is no recovery. Like you have been arguing, there aren't many places like that. So don't use it. --- 9 out of 10 times when I see an assert in code review I ask the author to reconsider. Often it only requires a little tweak. I guess you could say I have found asserts to be misused.