Re: Does D programming language have work steal queue?

2022-06-05 Thread mw via Digitalmars-d-learn

I will try it.


It's in dub now:

https://code.dlang.org/packages/liblfdsd


Also added queue_umm: unbounded,manyproducer,many_consumer, 
lock-free queue






Re: Comparing Exceptions and Errors

2022-06-05 Thread Ola Fosheim Grøstad via Digitalmars-d-learn

On Sunday, 5 June 2022 at 03:43:16 UTC, Paul Backus wrote:

See here:

https://bloomberg.github.io/bde-resources/pdfs/Contracts_Undefined_Behavior_and_Defensive_Programming.pdf


Not all software is banking applications. If an assert fails that 
means that the program logic is wrong, not that the program is in 
an invalid state. (Invalid state is a stochastic consequence and 
detection can happen mich later).


So that means that you should just stop the program. It means 
that you should shut down all running instances of that program 
on all computers across the globe. That is the logical 
consequence of this perspective, and it makes sense for a banking 
database.


It does not make sense for the constructor of Ants in a computer 
game service.


It is better to have an enjoyable game delivered with fewer ants 
than a black screen all weekend.


You can make the same argument for an interpreter: if an assert 
fails in the intrrpreter code then that could be a fault in the 
interpreter therefore you should shut down all programs being run 
by that interpreter.


The reality is that software is layered. Faults at different 
layers should have different consequences at the discretion of a 
capable programmer.




Re: Comparing Exceptions and Errors

2022-06-05 Thread Sebastiaan Koppe via Digitalmars-d-learn

On Sunday, 5 June 2022 at 06:31:42 UTC, Ola Fosheim Grøstad wrote:

On Sunday, 5 June 2022 at 00:40:26 UTC, Ali Çehreli wrote:
That is not very probable in 100% @safe code. You are basically 
saying that D cannot compete with Go and other «safe» languages.


Go has panic. Other languages have similar constructs.

So D will never be able to provide actors and provide fault 
tolerance.


I guess it depends on the programmer.



Is the service in a usable state?


Yes, the actor code failed. The actor code change frequently, 
not the runtime kernel.


The actor code is free to call anything, including @system code.

How would the actor framework know when an error is due to a 
silly bug in an isolated function or if it is something more 
serious?


Re: Comparing Exceptions and Errors

2022-06-05 Thread Ola Fosheim Grøstad via Digitalmars-d-learn

On Sunday, 5 June 2022 at 07:21:18 UTC, Ola Fosheim Grøstad wrote:
You can make the same argument for an interpreter: if an assert 
fails in the intrrpreter code then that could be a fault in the 
interpreter therefore you should shut down all programs being 
run by that interpreter.


Typo: if an assert fails in the interpreted code, then that could 
be a sign that the interpreter itself is flawed. Should you then 
stop all programs run by that interpreter?


The point: in the real world you need more options than the 
nuclear option. Pessimizing everywhere is not giving higher 
satisfaction for the end user.


(Iphone keyboard)


Re: Comparing Exceptions and Errors

2022-06-05 Thread Ola Fosheim Grøstad via Digitalmars-d-learn

On Sunday, 5 June 2022 at 07:28:52 UTC, Sebastiaan Koppe wrote:

Go has panic. Other languages have similar constructs.


And recover.

So D will never be able to provide actors and provide fault 
tolerance.


I guess it depends on the programmer.


But it isn’t if you cannot prevent Error from propagating.


Is the service in a usable state?


Yes, the actor code failed. The actor code change frequently, 
not the runtime kernel.


The actor code is free to call anything, including @system


@trusted code. How is this different from FFI in other languages? 
As a programmer you make a judgment. The D argument is to prevent 
the programmer from making a judgment?


How would the actor framework know when an error is due to a 
silly bug in an isolated


How can I know that a failure in Python code isn’t caused by C

There is no difference in the situation. I make a judgment as a 
programmer.


Re: Comparing Exceptions and Errors

2022-06-05 Thread Ola Fosheim Grøstad via Digitalmars-d-learn

On Sunday, 5 June 2022 at 00:18:43 UTC, Adam Ruppe wrote:

Run it in a separate process with minimum shared memory.


That is a workaround that makes other languages more attractive. 
It does not work when I want to have 1000+ actors in my game 
server (which at this point most likely will be written in Go, 
sadly).


So a separate process is basically a non-solution. At this point 
Go seems to be the best technology of all the bad options! A 
pity, as it is not an enjoyable language IMO, but the goals are 
more important than the means…


The problem here is that people are running an argument as if 
most D software is control-software for chemical processes or 
database kernels. Then people quote writings on safety measures 
that has been evolved in the context/mindset of control-software 
in the 80s and 90s. And that makes no sense, when only Funkwerk 
(and possibly 1 or 2 others) write such software in D.


The reality is, most languages call C-libraries and have C-code 
in their runtime, under the assumption that those C-libaries and 
runtimes have been hardened and proven to be reliable with low 
probability of failure.


*Correctness **is** probabilistic.* Even in the case of 100% 
verified code, as there is a possibility that the spec is wrong.


*Reliability measures are dependent on the used context*. What 
«reliable» means depends on skilled judgment utilized to evaluate 
the software in the use context. «reliable» is not a context 
independent absolute.






How to call a GDI+ function from D ?

2022-06-05 Thread Vinod K Chandran via Digitalmars-d-learn

Hi all,
I want to call the Bitmap function from gdi+. This is the syntax 
of the function in C++.

```c++
void Bitmap(
  [in] const WCHAR *filename,
  [in] BOOLuseEmbeddedColorManagement
);
```
And this is the mangled name which I got from goldbolt compiler.
`?Bitmap@@YAXPEB_WH@Z `

Now, this is my declaration in D.
```d
extern (C++, "Bitmap") void * Bitmap(const(wchar)* file, BOOL 
useClr);

```
And this is my call site.
```d
auto imgPath = toUTF16z(r"C:\Users\AcerLap\Pictures\Saved 
Pictures\d3.png") ;

auto pBmp = Bitmap(imgPath, FALSE);
```
But I got this error message.
```
app.obj : error LNK2019: unresolved external symbol "void * 
__cdecl Bitmap::Bitmap(char16_t const *,int)" 
(?Bitmap@0@YAPAXPB_SH@Z) referenced in function 
__D4wing9imagelist9ImageList8addImageMFAyaZv

app.exe : fatal error LNK1120: 1 unresolved externals
Error: linker exited with status 1120
```
You see, the mangled names are different.
From D - `?Bitmap@0@YAPAXPB_SH@Z`
From C++ - `?Bitmap@@YAXPEB_WH@Z`
How to fix this ?



Re: How to call a GDI+ function from D ?

2022-06-05 Thread rikki cattermole via Digitalmars-d-learn

Bitmap is a class, not a namespace.

The function you want is actually a constructor.

https://github.com/Alexpux/mingw-w64/blob/master/mingw-w64-headers/include/gdiplus/gdiplusheaders.h#L179


Re: Comparing Exceptions and Errors

2022-06-05 Thread Adam D Ruppe via Digitalmars-d-learn

On Sunday, 5 June 2022 at 10:38:44 UTC, Ola Fosheim Grøstad wrote:

That is a workaround that makes other languages more attractive.


It is what a lot of real world things do since it provides 
additional layers of protection while still being pretty easy to 
use.


*Correctness **is** probabilistic.* Even in the case of 100% 
verified code, as there is a possibility that the spec is wrong.


I'm of the opinion that the nothrow implementation right now is 
misguided. It is a relatively recent change to dmd (merged 
December 2017).


My code did and still does simply catch Error and proceed. Most 
Errors are completely harmless; RangeError, for example, is 
thrown *before* the out-of-bounds write, meaning it prevented the 
damage, not just notified you of it. It was fully recoverable in 
practice before that silly Dec '17 dmd change, and tbh still is 
after it in a lot of code.


If it was up to me, that patch would be reverted and the spec 
modified to codify the old status quo. Or perhaps redefine 
RangeError into RangeException, OutOfMemoryError as 
OutOfMemoryException, and such for the other preventative cases 
and carry on with joy, productivity, and correctness.


Re: How to call a GDI+ function from D ?

2022-06-05 Thread Vinod K Chandran via Digitalmars-d-learn

On Sunday, 5 June 2022 at 10:57:16 UTC, rikki cattermole wrote:

Bitmap is a class, not a namespace.

The function you want is actually a constructor.

https://github.com/Alexpux/mingw-w64/blob/master/mingw-w64-headers/include/gdiplus/gdiplusheaders.h#L179


Thank you for the reply. Well, I know that it is a CTOR. But I 
thought this is the D way to call it.


Re: Comparing Exceptions and Errors

2022-06-05 Thread Ola Fosheim Grøstad via Digitalmars-d-learn

On Sunday, 5 June 2022 at 11:13:48 UTC, Adam D Ruppe wrote:
On Sunday, 5 June 2022 at 10:38:44 UTC, Ola Fosheim Grøstad 
wrote:
That is a workaround that makes other languages more 
attractive.


It is what a lot of real world things do since it provides 
additional layers of protection while still being pretty easy 
to use.


Yes, it is not a bad solution in many cases. It is a classic 
solution for web servers, but web servers typically don't retain 
a variety of mutable state of many different types (a webserver 
can do well with just a shared memcache).



My code did and still does simply catch Error and proceed. Most 
Errors are completely harmless; RangeError, for example, is 
thrown *before* the out-of-bounds write, meaning it prevented 
the damage, not just notified you of it. It was fully 
recoverable in practice before that silly Dec '17 dmd change, 
and tbh still is after it in a lot of code.


Yes, this is pretty much how I write validators of input in 
Python web services. I don't care if the validator failed or if 
the input failed, in either case the input has to be stopped, but 
the service can continue. If there is a suspected logic failure, 
log and/or send notification to the developer, but for the end 
user it is good enough that they "for now" send some other input 
(e.g. avoiding some unicode letter or whatever).



Or perhaps redefine RangeError into RangeException, 
OutOfMemoryError as OutOfMemoryException, and such for the 
other preventative cases and carry on with joy, productivity, 
and correctness.


For a system level language such decisions ought to be in the 
hand of the developer so that he can write his own runtime. Maybe 
some kind of transformers so that libraries can produce Errors, 
but have them transformed to something else at boundaries.


If I want to write an actor-based runtime and do all my 
application code as 100% @safe actors that are fully «reliable», 
then that should be possible in a system level language.


The programmer's definition and evaluation of «reliability» in 
the context of a «casual game server» should carry more weight 
than some out-of-context-reasoning about «computer science» (it 
isn't actually).





Re: Comparing Exceptions and Errors

2022-06-05 Thread kdevel via Digitalmars-d-learn

On Sunday, 5 June 2022 at 00:40:26 UTC, Ali Çehreli wrote:
[...]
Errors are thrown when the program is discovered to be in an 
invalid state.


The following program throws an `Error` in popFront:

   import std.range;

   void main ()
   {
  int [1] a;
  auto q = a[1..$]; // line 6
  q.popFront;   // line 7, throws 
core.exception.AssertError

   }

When the program counter (PC) is at line 6 the program is in a 
valid state.


At no time the program is in an invalid state and it would not 
pass into an invalid state if popFront threw an `Exception` 
instead of an `Error`.


Re: Comparing Exceptions and Errors

2022-06-05 Thread kdevel via Digitalmars-d-learn
On Sunday, 5 June 2022 at 01:43:06 UTC, Steven Schveighoffer 
wrote:


[...]

But you aren't perfect, and so maybe you make a mistake, and 
trigger an Error. The compiler handles this unexpected 
condition by unwinding the stack back to the main function, 
printing the error and exiting, so you can go fix whatever 
mistake you made.


For this purpose nobody needs a separate subclass named `Error`. 
That works with `Exception`s.


[...]

If the code threw an `Exception` instead of an `Error` 
everything would be fine.


I think the point of Errors is that you can remove them for 
efficiency.


elephant/room.

In other words, just like asserts or bounds checks, they are 
not expected to be part of the normal working program.


"removing [Errors, asserts, bounds checks] is a bit like wearing 
a life-jacket to practice in the harbour, but then leaving the 
life-jackets behind when your ship leaves for open ocean" [1]


[...]

Consider the normal flow of a range in a foreach loop, it's:

```d
// foreach(elem; range)
for(auto r = range; !r.empty; r.popFront) {
auto elem = r.front;
}
```

If both `popFront` and `front` also always call `empty` you are 
calling `empty` 3 times per loop, with an identical value for 
the 2nd and 3rd calls.


Solution: Implement explicitly unchecked popFront() and front() 
versions.


Having the assert allows diagnosing invalid programs without 
crashing your program,


That depends on the understanding of "crashing a program". If 
library code throws an `Error` instead of an `Exception` I have 
to isolate that code in a subprocess in order to make my program 
gracefully handle the error condition.


Think of CGI processes which provide output direct to a customer. 
If there is an assert the customer will see the famous Internal 
Server Error message (in case of apache httpd).


[...]

[1] http://wiki.c2.com/?AssertionsAsDefensiveProgramming


Re: Comparing Exceptions and Errors

2022-06-05 Thread kdevel via Digitalmars-d-learn

On Sunday, 5 June 2022 at 07:21:18 UTC, Ola Fosheim Grøstad wrote:
[...]
The reality is that software is layered. Faults at different 
layers should have different consequences at the discretion of 
a capable programmer.


+1


Re: Comparing Exceptions and Errors

2022-06-05 Thread Ali Çehreli via Digitalmars-d-learn

On 6/4/22 23:31, Ola Fosheim Grøstad wrote:
> On Sunday, 5 June 2022 at 00:40:26 UTC, Ali Çehreli wrote:
>> Errors are thrown when the program is discovered to be in an invalid
>> state. We don't know what happened and when. For example, we don't
>> know whether the memory has been overwritten by some rogue code.
>
> That is not very probable in 100% @safe code. You are basically saying
> that D cannot compete with Go and other «safe» languages.

I did not mean that. I think we have a misunderstanding at a fundamental 
level.


> Dereferencing
> a null pointer usually means that some code failed to create an instance
> and check for it.

Dereferencing a null pointer does not throw Error but fine. I agree.

>> What happened? What can we assume. We don't know and we cannot assume
>> any state.
>
> So D will never be able to provide actors and provide fault tolerance.

Let me show an example. Here is a piece of code that could be running in 
an actor:


struct S {
  int[] a;
  int[] b;

  void add(int i) {// <-- Both arrays always same size
a ~= i;
b ~= i * 10;
  }

  void foo() {
assert(a.length == b.length);  // <-- Invariant check
// ...
  }
}

void main() {
  auto s = S();
  s.add(42);
  s.foo();
}

The code is written in a way that both arrays will *always* have equal 
number of elements. And there is a "silly" check for that invariant. So 
far so good. The issue is what to do *when* that assert fails.


Are you sure that it was a silly programmer mistake? I am not sure at all.

>> Is the service in a usable state?
>
> Yes, the actor code failed. The actor code change frequently, not the
> runtime kernel.

Is the only other culprit the runtime kernel? I really don't know who 
else may be involved.


>> Possibly. Not shutting down might produce incorrect results. Do we
>> prefer up but incorrect or dead?
>
> I prefer that service keeps running: chat service, game service, data
> delivered with hashed «checksum». Not all software are database engines
> where you have to pessimize about bugs in the runtime kernel.

There are also bugs in unrelated actor code writing over each others' 
memory.


It is possible that the service will do unexpected or very wrong things. 
But you answer my question: Your game server can do weird things. 
Hopefully all acceptable by paying customers.


> If the data delivered is good enough for the client and better than
> nothing then the service should keep running!!!

Yes! How can you be sure data is good when the silly assertion above 
failed. How could that happen? Is there any logical way to describe it 
was actor code's mistake? I don't think so. Let's assume the 
commented-out parts do not touch the arrays at all.


You are free to choose to catch Errors and continue under the assumption 
that it is safe to do so. The advice in the article still holds for me. 
I think the main difference is in the assumptions we make about an 
Errors: Is it a logic error in actor code or some crazy state that will 
cause weirder results if we continue. We can't know for sure.


>> I hope there is a way of aborting the program when there are invariant
>
> Invariants are USUALLY local. I dont write global spaghetti code. As a
> programmer you should be able to distinguish between local and global
> failure.
>
> You are assuming that the programmer is incapable of making judgements.
> That is assuming way too much.

I resent causing that misunderstanding. I apologize.

The only assumption I make about the programmer is that they do not mix 
Error and Exception so that in the end an Error points at a situation 
that warrants aborting the mission. Hm... Thinking more about it, 
assuming that an Error is due to a local programmer error would be a 
judgment.


Ali



Re: Comparing Exceptions and Errors

2022-06-05 Thread Ali Çehreli via Digitalmars-d-learn

On 6/5/22 04:43, kdevel wrote:
> On Sunday, 5 June 2022 at 00:40:26 UTC, Ali Çehreli wrote:
> [...]
>> Errors are thrown when the program is discovered to be in an invalid
>> state.
>
> The following program throws an `Error` in popFront:
>
> import std.range;
>
> void main ()
> {
>int [1] a;
>auto q = a[1..$]; // line 6
>q.popFront;   // line 7, throws core.exception.AssertError
> }
>
> When the program counter (PC) is at line 6 the program is in a valid 
state.

>
> At no time the program is in an invalid state and it would not pass into
> an invalid state if popFront threw an `Exception` instead of an `Error`.

That looks like an argument for changing the behavior of D runtime when 
an out-of-bounds access occurs. Of course, it is too late to change that 
at this time but perhaps there can be a compiler switch like 
-boundstype=[error|exception].


The programmer has many options to prove that nothing crazy is 
happening. A common example suitable for many cases:


  enforce(!q.empty); // (Throws Exception)
  q.popFront;

Ali



Re: Comparing Exceptions and Errors

2022-06-05 Thread kdevel via Digitalmars-d-learn

On Sunday, 5 June 2022 at 14:24:39 UTC, Ali Çehreli wrote:
[...]

struct S {
  int[] a;
  int[] b;

  void add(int i) {// <-- Both arrays always same size
a ~= i;
b ~= i * 10;
  }

  void foo() {
assert(a.length == b.length);  // <-- Invariant check
// ...
  }
}

void main() {
  auto s = S();
  s.add(42);
  s.foo();
}

The code is written in a way that both arrays will *always* 
have equal number of elements.


I think this is what Sean Parent called "incidental data 
structure" [1]. I would refactor the code:


struct T {
   int a;
   int b;
}

struct S {
   T [] t;

  void add(int i) {
t ~= T (i, i * 10);
  }

  void foo() {
// Look Ma no assert!
// ...

  }
}

void main() {
  auto s = S();
  s.add(42);
  s.foo();
  s.a ~= 1; // does not compile
  s.foo();
}
```
[1] 


Copy Constructor

2022-06-05 Thread Salih Dincer via Digitalmars-d-learn

Hi,

Let be the structure Foo that wraps an int pointer. Let's setup 
Foo in 3 different ways:

1. Foo one = Foo(1);
2. Foo two = 2;
3. [ Foo(3) ];


Pretty clean, right?

So why it's not run copy-constructor in 3? Also, when we write to 
the screen with writeln(), why four times copy-constructors are 
running?


**Playground:** https://run.dlang.io/is/qHvLJe
**Source:**
```d
struct Foo {
  int payload;

  this(int i)
  {
this.payload = i;
  }

  this(ref return scope Foo that)
  {
this = that; //cC = copyConstructor
logger ~= format("cC(%s)", that.payload);
  }

  Foo opUnary(string op)()
  if(op == "++") {
++this.payload;
return this;
  }

  int getter()
  {
return payload;
  }
  alias getter this;
}

import std.stdio, std.format;
string logger;

void main() {
  Foo one = Foo(1), two = 2;
  int[] arr = [one, two, Foo(3)];

  auto three = ++two;/*
  two.writeln(": 0x", &two.payload);//*/

  //arr.writeln;/*
  foreach(ref i; arr) {
i.writeln(": 0x", &i);
  }//*/

  writeln("0x", &three.payload);

  logger.writeln;
} // end with the logger!
/*
Print Outs:
=
1: 0x7FD13D561000
2: 0x7FD13D561004
3: 0x7FD13D561008
0x7FFE6757E908
cC(1)cC(2)cC(3)
*/
```

SDB@79


Re: Comparing Exceptions and Errors

2022-06-05 Thread matheus via Digitalmars-d-learn

On Sunday, 5 June 2022 at 15:07:13 UTC, kdevel wrote:

... I would refactor the code:


I really liked this one. The way it solves and at same time 
restrict the "external access" with that struct of (a,b) makes 
the code easier to maintain too.


Glad I keep lurking around this forum.

Matheus.


Re: Comparing Exceptions and Errors

2022-06-05 Thread Ola Fosheim Grøstad via Digitalmars-d-learn
Ok, so I am a bit confused about what is Error and what is not… 
According to core.exception there is wide array of runtime Errors:


```
RangeError
ArrayIndexError
ArraySliceError
AssertError
FinalizeError
OutOfMemoryError
InvalidMemoryOperationError
ForkError
SwitchError
```

I am not sure that any of these should terminate anything outside 
the offending actor, but I could be wrong as it is hard to tell 
exactly when some of those are thrown.


InvalidMemoryOperationError sound bad, of course, but the docs 
says «An invalid memory operation error occurs in circumstances 
when the garbage collector has detected an operation it cannot 
reliably handle. The default D GC is not re-entrant, so this can 
happen due to allocations done from within finalizers called 
during a garbage collection cycle.»


This sounds more like an issue that needs fixing…


On Sunday, 5 June 2022 at 14:24:39 UTC, Ali Çehreli wrote:
The code is written in a way that both arrays will *always* 
have equal number of elements. And there is a "silly" check for 
that invariant. So far so good. The issue is what to do *when* 
that assert fails.


Are you sure that it was a silly programmer mistake? I am not 
sure at all.


Ok, so this is a question of the layers:

```
 top layer --
D  | E
   |
- middle layer --
B  | C
   |
   |
 bottom layer ---
A



If the failed assert is happening in a lower layer A then code on 
the outer layer should fault (or roll back a transaction). 
Whether it is reasonable to capture that error and suppress it 
depends on how independent you want those layers to be in your 
architecture. It also depends on the nature of layer A.


If the failed assert happens in middle layer section B, then the 
D would be affected, but not A, C or E.


The key issue is that the nature of layers is informal in the 
language (in fact, in most languages, a weakness), so only the 
programmer can tell what is reasonable or not.


In fact, when we think about it; most aspects about what is 
expected from a program is informal… so it is very difficult to 
make judgment at the compiler level.


Is the only other culprit the runtime kernel? I really don't 
know who else may be involved.


I mean the application's «custom actor kernel», a hardened piece 
of code that is not modified frequently and heavily tested. The 
goal is to keep uncertainty local to an actor so that you can 
toss out misbehaving actors and keep the rest of the system 
working smoothly (99.5% of the time, 50 minutes downtime per 
week).


Actors are expected to contain bugs because the game system is 
continuously modified (to balance the game play, to get new 
content, more excitement, whatever…). This is why we want 100% 
@safe code as a feature.



There are also bugs in unrelated actor code writing over each 
others' memory.


But that cannot happen if I decide to make actors 100% @safe and 
only let them interact with each other through my «custom actor 
kernel»?



You are free to choose to catch Errors and continue under the 
assumption that it is safe to do so.


Now I am confused!! Steven wrote «I've thought in the past that 
throwing an error really should not throw, but log the error 
(including the call stack), and then exit without even attempting 
to unwind the stack.»


Surely, the perspective being promoted is to make sure that 
Errors cannot be stopped from propagating? That is why this 
becomes a discussion?


If an Error can propagate through "nothrow" then the compiler 
should emit handler code for it and issue a warning. If you don't 
want that then the programmer should safe guard against it, 
meaning: manually catch and abort or do manual checks in all 
locations above it where Errors can arise. The compiler knows 
where.


Not really sure why D has "nothrow", it doesn't really fit with 
the rest of the language? To interface with C++ perhaps?? If that 
is the case, just adopt C++ "noexcept" semantics, use assert() 
for debugging only, in "nothrow" code. And discourage the use of 
"nothrow". Heck, throw in a compiler switch to turn off "nothrow" 
if that is safe.



The advice in the article still holds for me. I think the main 
difference is in the assumptions we make about an Errors: Is it 
a logic error in actor code or some crazy state that will cause 
weirder results if we continue. We can't know for sure.


And this is no different from other languages with a runtime. You 
cannot be sure, but it probably isn't a runtime issue, and even 
if it was… players will be more upset by not being able to play 
than to have some weird effects happening. Same for chat service. 
Same for being able to read Wikipedia-caches (worse to have no 
access than to have 1% of pages garbled on display until the 
server is updated).


Different settings need different solutions. So, maybe 
interfacing with C++ requires "nothrow", but if that is the only 
reason… why let everybody pay a pric

Re: Comparing Exceptions and Errors

2022-06-05 Thread Ali Çehreli via Digitalmars-d-learn

On 6/5/22 08:07, kdevel wrote:
> On Sunday, 5 June 2022 at 14:24:39 UTC, Ali Çehreli wrote:
> [...]
>> struct S {
>>   int[] a;
>>   int[] b;
>>
>>   void add(int i) {// <-- Both arrays always same size
>> a ~= i;
>> b ~= i * 10;
>>   }
>>
>>   void foo() {
>> assert(a.length == b.length);  // <-- Invariant check
>> // ...
>>   }
>> }
>>
>> void main() {
>>   auto s = S();
>>   s.add(42);
>>   s.foo();
>> }
>>
>> The code is written in a way that both arrays will *always* have equal
>> number of elements.
>
> I think this is what Sean Parent called "incidental data structure" [1].

Like many other programmers who include me, Sean Parent may be right.[1]

Other than being a trivial example to make a point, the code I've shown 
may be taking advantage of the "structure of array" optimization. I am 
sure Sean Parent knows that as well.


> I would refactor the code:

Most likely me too.

> struct T {
> int a;
> int b;
> }
>
> struct S {
> T [] t;
>
>void add(int i) {
>  t ~= T (i, i * 10);
>}
>
>void foo() {
>  // Look Ma no assert!

The assert may have been moved to another place:

struct T {
int a;
int b;

  invariant() {
// Look Pa it's still here!
assert(b == a * 10);
  }
}

Ali

[1] I stopped following Sean Parent when he dismissed D and me by waving 
his hand behind and walking away: "A language with reference types? No, 
thanks." That happened at the end of one of his presentations here at 
the Silicon Valley C++, which I happened to co-host. I am sure he is 
observant enough to one day realize that C++ has reference types by 
convention. (I recently posted links to C++ core guidelines proving that 
point of mine, one of which is something to the effect of "never pass 
polymorphic types by-value".)




Re: How to call a GDI+ function from D ?

2022-06-05 Thread Vinod K Chandran via Digitalmars-d-learn

On Sunday, 5 June 2022 at 11:33:14 UTC, Vinod K Chandran wrote:




For future readers of this thread, rikki cattermole helped me to 
findthe solution to this problem. I Do not need the C++ classes 
or their methods for this. There is a set of C functions in 
gdiplus.dll. Check this link. 
https://docs.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-flatapi-flat





Re: Comparing Exceptions and Errors

2022-06-05 Thread Ola Fosheim Grøstad via Digitalmars-d-learn

On Sunday, 5 June 2022 at 14:24:39 UTC, Ali Çehreli wrote:

  void add(int i) {// <-- Both arrays always same size
a ~= i;
b ~= i * 10;
  }

  void foo() {
assert(a.length == b.length);  // <-- Invariant check
// ...
  }


Maybe it would help if we can agree that this assert ought to be 
statically proven to hold and the assert would therefore never be 
evaluated in running code. Emitting asserts is just a sign of 
failed statical analysis (which is common, but that is the most 
sensible interpretation from a verification viewpoint).


The purpose of asserts is not to test the environment. The 
purpose is to "prove" that the specified invariant of the 
function holds for all legal input.


It follows that the goal of an assert is not to test if the 
program is in a legal state!


I understand why you say this, but if this was the case then we 
could not remove any asserts by statical analysis. :-/




Re: Comparing Exceptions and Errors

2022-06-05 Thread kdevel via Digitalmars-d-learn

On Sunday, 5 June 2022 at 17:04:49 UTC, Ali Çehreli wrote:

On 6/5/22 08:07, kdevel wrote:

[...]
Like many other programmers who include me, Sean Parent may be 
right.[1]


Other than being a trivial example to make a point, the code 
I've shown may be taking advantage of the "structure of array" 
optimization.


"Premature optimization is ..."

[...]

> struct T {
> int a;
> int b;
> }
>
> struct S {
> T [] t;
>
>void add(int i) {
>  t ~= T (i, i * 10);
>}
>
>void foo() {
>  // Look Ma no assert!

The assert may have been moved to another place:


It's not "the" assert but another one. Nonetheless I take up the 
challenge:



struct T {
int a;
int b;

  invariant() {
// Look Pa it's still here!
assert(b == a * 10);
  }
}


struct T {
int i;
this (int i)
{
this.i = i;
import std.checkedint;
Checked!(int, Throw) (i) * 10;
}
int a () const { return i; }
int b () const { return i * 10; }
}
struct S {
const (T) [] t;
void add(int i) {// <-- Both arrays always same size
   t ~= T (i);
}
void foo() {
   // ...
}
}

void main() {
  auto s = S();
  s.add(42);
  s.foo();
//  s.a ~= 1; // does not compile
//  s.t[0].b = 3; // no compile either
//  s.t[0].i = 7; // cannot change i, does not compile
  s.add (2^^27); // fine
//  s.add (2^^28); // throws Overflow on binary operator, fine
  s.foo();
}


Ali


[...]

I'll try to not bring up his name again ;-)




Re: Copy Constructor

2022-06-05 Thread Alain De Vos via Digitalmars-d-learn

I don't know the answer. But some questions come to my mind.
Does Foo(3) lives on the stack or the heap ?
There is also no assignment from Foo to Foo for Foo(3), there is 
a conversion.

And what happes with
Foo[3] arr = [one, two, Foo(3)];
Foo[]  arr=   [one, two, Foo(3)];
and
Foo x=Foo(3).dup()



Re: Copy Constructor

2022-06-05 Thread Salih Dincer via Digitalmars-d-learn

On Sunday, 5 June 2022 at 15:45:17 UTC, Salih Dincer wrote:

Hi,

Let be the structure Foo that wraps an int pointer. Let's setup 
Foo in 3 different ways:

1. Foo one = Foo(1);
2. Foo two = 2;
3. [ Foo(3) ];


There is a fourth possibility:
```d
int[] arr = [ one, two, Foo(3), *(new Foo(4)) ];
```
The 1st, 2nd and 4th elements of array are copied, but the 3rd 
element is not. Could it have something to do with CTFE?

https://tour.dlang.org/tour/en/gems/compile-time-function-evaluation-ctfe

SDB@79


Re: Copy Constructor

2022-06-05 Thread Paul Backus via Digitalmars-d-learn

On Sunday, 5 June 2022 at 18:50:13 UTC, Salih Dincer wrote:

On Sunday, 5 June 2022 at 15:45:17 UTC, Salih Dincer wrote:

Hi,

Let be the structure Foo that wraps an int pointer. Let's 
setup Foo in 3 different ways:

1. Foo one = Foo(1);
2. Foo two = 2;
3. [ Foo(3) ];


There is a fourth possibility:
```d
int[] arr = [ one, two, Foo(3), *(new Foo(4)) ];
```
The 1st, 2nd and 4th elements of array are copied, but the 3rd 
element is not. Could it have something to do with CTFE?

https://tour.dlang.org/tour/en/gems/compile-time-function-evaluation-ctfe


Since the 3rd element is an rvalue, it is moved into the array 
rather than copied.


Re: Copy Constructor

2022-06-05 Thread Salih Dincer via Digitalmars-d-learn

On Sunday, 5 June 2022 at 18:43:19 UTC, Alain De Vos wrote:

Does Foo(3) lives on the stack or the heap ?


Definitely not stack because that's what happens when the new 
operator is used. Article 14.3: 
https://dlang.org/spec/struct.html#intro


SDB@79


Re: Comparing Exceptions and Errors

2022-06-05 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/5/22 8:45 AM, kdevel wrote:

On Sunday, 5 June 2022 at 01:43:06 UTC, Steven Schveighoffer wrote:

[...]

But you aren't perfect, and so maybe you make a mistake, and trigger 
an Error. The compiler handles this unexpected condition by unwinding 
the stack back to the main function, printing the error and exiting, 
so you can go fix whatever mistake you made.


For this purpose nobody needs a separate subclass named `Error`. That 
works with `Exception`s.


You can use Exceptions instead. But the difference is they are part of 
the program instead of considered a check on the program itself.


There's a need for both.



[...]

If the code threw an `Exception` instead of an `Error` everything 
would be fine.


I think the point of Errors is that you can remove them for efficiency.


elephant/room.


Why? If you have a correct program, you shouldn't ever have errors 
thrown. If you do have errors thrown that's something you need to 
address ASAP.




In other words, just like asserts or bounds checks, they are not 
expected to be part of the normal working program.


"removing [Errors, asserts, bounds checks] is a bit like wearing a 
life-jacket to practice in the harbour, but then leaving the 
life-jackets behind when your ship leaves for open ocean" [1]


It's more like leaving the floaties behind when you are doing a swim meet.



[...]

Consider the normal flow of a range in a foreach loop, it's:

```d
// foreach(elem; range)
for(auto r = range; !r.empty; r.popFront) {
    auto elem = r.front;
}
```

If both `popFront` and `front` also always call `empty` you are 
calling `empty` 3 times per loop, with an identical value for the 2nd 
and 3rd calls.


Solution: Implement explicitly unchecked popFront() and front() versions.


That's terrible. Now I have to instrument my code whenever I have a 
weird unknown error, changing all range functions to use the 
`checkedPopFront` and `checkedFront`, just to find the error. Instead of 
letting the asserts do their job.




Having the assert allows diagnosing invalid programs without crashing 
your program,


That depends on the understanding of "crashing a program". If library 
code throws an `Error` instead of an `Exception` I have to isolate that 
code in a subprocess in order to make my program gracefully handle the 
error condition.


You don't gracefully handle the error condition. It's like saying 
gracefully handling running into the guardrail on a road. You just 
crash, and hope you don't die. You don't just graze into it and keep 
going thinking "well, the guardrail did it's job, glad it's there, I 
plan on using it every time I go around that corner."




Think of CGI processes which provide output direct to a customer. If 
there is an assert the customer will see the famous Internal Server 
Error message (in case of apache httpd).


An assert triggering means, your code did something invalid. It should 
crash/exit.


Now we can have *totally separate* debates on what should be an Error 
and what should be an Exception. And not to belittle your point, I 
understand that there can be a philosophy that you *only* want 
recoverable throwables for certain code domains (I myself also have that 
feeling for e.g. out of bounds errors). It's just not what D picked as 
an error handling scheme. We have both recoverable exceptions, and non 
recoverable errors.


-Steve


Re: Copy Constructor

2022-06-05 Thread Alain De Vos via Digitalmars-d-learn
Could it be the copy constructor is only called during 
assignments (like C++).

And for one, two there is an explicit assignment.
But not for three where there is a conversion ?



Re: Comparing Exceptions and Errors

2022-06-05 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/5/22 12:27 PM, Ola Fosheim Grøstad wrote:
Ok, so I am a bit confused about what is Error and what is not… 
According to core.exception there is wide array of runtime Errors:


```
RangeError
ArrayIndexError
ArraySliceError
AssertError
FinalizeError
OutOfMemoryError
InvalidMemoryOperationError
ForkError
SwitchError
```

I am not sure that any of these should terminate anything outside the 
offending actor, but I could be wrong as it is hard to tell exactly when 
some of those are thrown.


Just FYI, this is a *different discussion* from whether Errors should be 
recoverable.


Whether specific conditions are considered an Error or an Exception is 
something on which I have differing opinions than the language.


However, I do NOT have a problem with having an assert/invariant 
mechanism to help prove my program is correct.


-Steve


Re: Comparing Exceptions and Errors

2022-06-05 Thread Ola Fosheim Grøstad via Digitalmars-d-learn
On Sunday, 5 June 2022 at 21:08:11 UTC, Steven Schveighoffer 
wrote:
Just FYI, this is a *different discussion* from whether Errors 
should be recoverable.


Ok, but do you a difference between being recoverable anywhere 
and being recoverable at the exit-point of an execution unit like 
an Actor/Task?


Whether specific conditions are considered an Error or an 
Exception is something on which I have differing opinions than 
the language.


Ok, like null-dereferencing and division-by-zero perhaps.

However, I do NOT have a problem with having an 
assert/invariant mechanism to help prove my program is correct.


Or rather the opposite, prove that a specific function is 
incorrect for a specific input configuration.


The question is, if a single function is incorrect for some 
specific input, why would you do anything more than disabling 
that function?





Re: Comparing Exceptions and Errors

2022-06-05 Thread Ali Çehreli via Digitalmars-d-learn

On 6/5/22 11:03, kdevel wrote:
> On Sunday, 5 June 2022 at 17:04:49 UTC, Ali Çehreli wrote:
>> On 6/5/22 08:07, kdevel wrote:
> [...]
>> Like many other programmers who include me, Sean Parent may be right.[1]
>>
>> Other than being a trivial example to make a point, the code I've
>> shown may be taking advantage of the "structure of array" optimization.
>
> "Premature optimization is ..."

You pulled important phrases like "Sean Parent" and "incidental data 
structure" and I countered with "structure of array" but "premature 
optimization" finally beat my argument. Wait... No! Proving my example 
ineffective does not disprove my argument. So, I take this exchange as a 
fun break.


> It's not "the" assert but another one. Nonetheless I take up the 
challenge:


I hereby withdraw my example.

Ali



Re: Copy Constructor

2022-06-05 Thread Ali Çehreli via Digitalmars-d-learn

On 6/5/22 14:04, Alain De Vos wrote:
> Could it be the copy constructor is only called during assignments (like
> C++).

The assignment operator is used during assignments both in C++ and D.

A confusion comes from the fact that construction uses the same operator 
as assignment:


  a = b;  // Assignment because 'a' already exists

  auto c = b; // Copy construction because 'c' is being constructed

> And for one, two there is an explicit assignment.

Actually, both are copy construction:

  Foo one = Foo(1), two = 2;

You will never find me write code like because it's unclear. My version 
would be the following:


  Foo one = Foo(1);
  Foo two = 2;

But even that is not my style because the first line repeats Foo and the 
second line hides the fact that there is construction. So, this is what 
I write in my programs:


  auto one = Foo(1);
  auto two = Foo(2);

> But not for three where there is a conversion ?

There are two "three"s in that code. The first one is construction (not 
copy):


  [one, two, Foo(3)]

And the other one is copy construction:

  auto three = ++two;

'two' is first incremented and then a copy is made from 'two's new state.

Ali



Re: Copy Constructor

2022-06-05 Thread Ali Çehreli via Digitalmars-d-learn

On 6/5/22 12:00, Salih Dincer wrote:
> On Sunday, 5 June 2022 at 18:43:19 UTC, Alain De Vos wrote:
>> Does Foo(3) lives on the stack or the heap ?

I depends. I will respond to your other message.

> Definitely not stack because that's what happens when the new operator
> is used. Article 14.3: https://dlang.org/spec/struct.html#intro

I think you meant the other way. It is *not* on the stack if you use new.

Ali



Re: Copy Constructor

2022-06-05 Thread Ali Çehreli via Digitalmars-d-learn

On 6/5/22 11:43, Alain De Vos wrote:

> Does Foo(3) lives on the stack or the heap ?

It depends.

> there is a
> conversion.

Suche conversions are called "construction" in D.

> And what happes with
> Foo[3] arr = [one, two, Foo(3)];

Foo[3] is a static array. Static arrays are value types. Their elements 
normally do not live on heap:


void foo() {
  Foo[3] arr;// On the stack
}

However, if Foo[3] were a member of something else

class C {
  int i;
  Foo[3] arr;
}

and if an object of C is constructed on heap

  auto c = new C();

then the Foo[3] member will also live on the heap alongside 'i'.

It could be the opposite: If the class object were emplaced on stack, 
then every member would we on the stack.


As you see, "on the stack" really depends.

Let's assume that your example is inside a function, i.e. the array is 
on the stack:


void foo() {
  Foo[3] arr = [one, two, Foo(3)];
}

Now all members of 'arr' on the stack. As 'one' and 'two' are lvalues, 
they are copied to arr[0] and arr[1]. But as Foo(3) is an rvalue, as 
Paul Backus said in the other message, that element is moved to arr[2].


So there are two copies and one move.

> Foo[]  arr=   [one, two, Foo(3)];

That one is different because Foo[] is a dynamic array that keeps its 
elements on the heap. That expression will allocate memory for at leasts 
3 elements and to the same: Two copies and one move.


> and
> Foo x=Foo(3).dup()

If there were a dup() member function of Foo:

struct Foo {
  Foo dup() {
return Foo(this.payload);
  }
}

In that case, as the returned object is an rvalue, it would be moved to 
'x'. The returned object could be an lvalue:


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'.


Ali



Re: Copy Constructor

2022-06-05 Thread Ali Çehreli via Digitalmars-d-learn

On 6/5/22 14:39, Ali Çehreli wrote:

> Actually, both are copy construction:

I am wrong there. I did confuse myself.

>Foo one = Foo(1), two = 2;

As my rewrite shows, they are both construction with an int:

>auto one = Foo(1);
>auto two = Foo(2);

Ali



Re: Comparing Exceptions and Errors

2022-06-05 Thread kdevel via Digitalmars-d-learn
On Sunday, 5 June 2022 at 20:53:32 UTC, Steven Schveighoffer 
wrote:

[...]
For this purpose nobody needs a separate subclass named 
`Error`. That works with `Exception`s.


You can use Exceptions instead. But the difference is they are 
part of the program instead of considered a check on the 
program itself.


I have no clue what that means.


[...]

If the code threw an `Exception` instead of an `Error` 
everything would be fine.


I think the point of Errors is that you can remove them for 
efficiency.


elephant/room.


Why? If you have a correct program, you shouldn't ever have 
errors thrown. If you do have errors thrown that's something 
you need to address ASAP.


My code does not throw `Error`s. It always throws `Exception`s.

In other words, just like asserts or bounds checks, they are 
not expected to be part of the normal working program.


"removing [Errors, asserts, bounds checks] is a bit like 
wearing a life-jacket to practice in the harbour, but then 
leaving the life-jackets behind when your ship leaves for open 
ocean" [1]


It's more like leaving the floaties behind when you are doing a 
swim meet.


Nice new question for job interviews.


[...]

Consider the normal flow of a range in a foreach loop, it's:

```d
// foreach(elem; range)
for(auto r = range; !r.empty; r.popFront) {
    auto elem = r.front;
}
```

If both `popFront` and `front` also always call `empty` you 
are calling `empty` 3 times per loop, with an identical value 
for the 2nd and 3rd calls.


Solution: Implement explicitly unchecked popFront() and 
front() versions.


That's terrible. Now I have to instrument my code whenever I 
have a weird unknown error,


Well, no. Just use the default. It will throw an exception if 
something goes wrong. Of course, I must admid, if you want to 
compete with those I-have-the-fastest-serving-http-server-guys 
(N.B.: HTTP not HTTPS! Did anybody notice that?) reporting 50 
Gigarequests per second (or so) then you probably have to 
*measure* *the* *performance* of the range/container 
implementation. But not earlier.


changing all range functions to use the `checkedPopFront` and 
`checkedFront`, just to find the error. Instead of letting the 
asserts do their job.


It is not clear to me, what you now complain about. You first 
criticized that in


```
for(auto r = range; !r.empty; r.popFront) {
   auto elem = r.front;
}
```

there is triple checking that r is not empty, namely in !r.empty, 
in r.front and in r.popFront. One check, !r.emtpy, will suffice. 
Hence one can safely use


```
for(auto r = range; !r.empty; r.popFront_unchecked) {
   auto elem = r.front_unchecked;
}
```

If you don't trust whomever you can simply keep the checked 
versions. The test will then be performed thrice regardless if a 
test failure will result in throwing an `Exception` or throwing 
an `Error`. AFAICS.


[...]


Re: Comparing Exceptions and Errors

2022-06-05 Thread kdevel via Digitalmars-d-learn
On Sunday, 5 June 2022 at 21:08:11 UTC, Steven Schveighoffer 
wrote:

[...]
Just FYI, this is a *different discussion* from whether Errors 
should be recoverable.


The wording of this "question" bothers me really. What does 
"Errors" mean here? If you mean thrown object having a (sub)type 
of `Error` the relevant question is:


   ARE `Error`s recoverable?

If they ARE recoverable then every program can written in a way 
it handles even `Error`s gracefully.


Whether specific conditions are considered an Error or an 
Exception is something on which I have differing opinions than 
the language.


However, I do NOT have a problem with having an 
assert/invariant mechanism to help prove my program is correct.


I may be not a top-notch expert on this topic but IMO there is no 
facility which can perform such a proof.







Re: Comparing Exceptions and Errors

2022-06-05 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/5/22 6:09 PM, kdevel wrote:

On Sunday, 5 June 2022 at 20:53:32 UTC, Steven Schveighoffer wrote:
[...]
For this purpose nobody needs a separate subclass named `Error`. That 
works with `Exception`s.


You can use Exceptions instead. But the difference is they are part of 
the program instead of considered a check on the program itself.


I have no clue what that means.


An assert (or thrown error) is not ever supposed to happen, so it's not 
part of the program. It's a check to ensure that the program is sound 
and valid. You can feel free to insert as many asserts as you want, and 
it should not be considered part of the program.


It basically says "If this condition is false, this entire program is 
invalid, and I don't know how to continue from here."





[...]

If the code threw an `Exception` instead of an `Error` everything 
would be fine.


I think the point of Errors is that you can remove them for efficiency.


elephant/room.


Why? If you have a correct program, you shouldn't ever have errors 
thrown. If you do have errors thrown that's something you need to 
address ASAP.


My code does not throw `Error`s. It always throws `Exception`s.


Then I guess you should just ignore Errors and let the runtime handle 
them? I'm not sure why this discussion is happening.



[...]

Consider the normal flow of a range in a foreach loop, it's:

```d
// foreach(elem; range)
for(auto r = range; !r.empty; r.popFront) {
    auto elem = r.front;
}
```

If both `popFront` and `front` also always call `empty` you are 
calling `empty` 3 times per loop, with an identical value for the 
2nd and 3rd calls.


Solution: Implement explicitly unchecked popFront() and front() 
versions.


That's terrible. Now I have to instrument my code whenever I have a 
weird unknown error,


Well, no. Just use the default. It will throw an exception if something 
goes wrong. Of course, I must admid, if you want to compete with those 
I-have-the-fastest-serving-http-server-guys (N.B.: HTTP not HTTPS! Did 
anybody notice that?) reporting 50 Gigarequests per second (or so) then 
you probably have to *measure* *the* *performance* of the 
range/container implementation. But not earlier.


It becomes a tedious job of me to check "did I already check this? Oh I 
did, so I can call the unchecked version", and hope that a future me 
doesn't remove the original check.


Just always check, and then if you care about performance turn the 
checks off. If they are on, and it crashes the program, you need to fix 
it before turning them off. It's never a solution to just turn the 
safety checks off when they are failing to allow the program to "work".




changing all range functions to use the `checkedPopFront` and 
`checkedFront`, just to find the error. Instead of letting the asserts 
do their job.


It is not clear to me, what you now complain about. You first criticized 
that in


```
for(auto r = range; !r.empty; r.popFront) {
    auto elem = r.front;
}
```

there is triple checking that r is not empty, namely in !r.empty, in 
r.front and in r.popFront. One check, !r.emtpy, will suffice. Hence one 
can safely use


```
for(auto r = range; !r.empty; r.popFront_unchecked) {
    auto elem = r.front_unchecked;
}
```


You can do this, and then if it fails, you have to guess that maybe you 
did something wrong, and start using the checked versions.


I have encountered numerous times when I trigger these checks, and it's 
always a problem with how I wrote my code. If instead I just got a 
segfault, now I have to start digging, instrumenting, etc.




If you don't trust whomever you can simply keep the checked versions. 
The test will then be performed thrice regardless if a test failure will 
result in throwing an `Exception` or throwing an `Error`. AFAICS.


As the author of the range, I put the asserts in for *my* benefit, 
without affecting the user (if they so desire). I never trust the user.


If you write perfect code, turn asserts off and you won't have a 
problem, right?


If you don't write perfect code, leave them on, and you can diagnose the 
problem when it occurs instead of having to redo everything.


The thing is, I don't want there to be a battle between performance and 
correctness. This solves the issue by allowing correctness to be 
checked, without hindering the possibility of compiling with performance.


Yet, I do think D compilers don't make it easy to turn off checks in 
selected module. And as previously stated, I think some things that are 
Errors should actually be Exceptions.


-Steve


Re: Comparing Exceptions and Errors

2022-06-05 Thread Ola Fosheim Grøstad via Digitalmars-d-learn
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.


Or in terms of actors/tasks: if one actor-solver fails 
numerically, then you can recover and use a different 
actor-solver.


An assert says nothing about the whole program.

An assert only says that the logic of that particular function is 
not meeting the SPEC.


That’s all. If you use asserts for something else then you don’t 
follow the semantic purpose of asserts.


Only the programmer knows if recovery is possible, not the 
compiler.


A failed assert is not implying undefined behaviour in @safe code.




Re: Comparing Exceptions and Errorsj

2022-06-05 Thread Ola Fosheim Grøstad via Digitalmars-d-learn

On Monday, 6 June 2022 at 04:59:05 UTC, Ola Fosheim Grøstad wrote:
An assert only says that the logic of that particular function 
is not meeting the SPEC.


Actually, the proper semantics are weaker than that, the spec 
would be preconditions and post conditions. Asserts are actually 
just steps to guide a solver to find a proof faster (or at all) 
for that particular function.


In practice asserts are «checked comments» about what the 
programmer assumed when he/she implemented the algorithm of that 
function.


A failed assert just says that the assumption was wrong.

If the compiler can prove that an assert holds given legal input, 
then it will be removed. As such, it follows that asserts has 
nothing to do with undefined behaviour in terms of illegal input. 
The assert is not there to guard against it so the compiler 
removed it as it assumes that the type constraints of the input 
holds.




Re: Comparing Exceptions and Errors

2022-06-05 Thread Sebastiaan Koppe via Digitalmars-d-learn

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.