Re: Flagging special conditions on return from a function call

2020-06-23 Thread Denis via Digitalmars-d-learn

On Tuesday, 23 June 2020 at 21:34:25 UTC, Paul Backus wrote:


If you're open to using Dub packages [...]


Because this is going to be used in almost every program I write, 
I need to eliminate outside dependencies as an option. 
Nonetheless, thanks for this suggestion.


[2] 
https://pbackus.github.io/blog/beating-stdvisit-without-really-trying.html


I did read your blog post: that's an impressive result. Good to 
know that well-written D code can be competitive with C.


Denis


Re: opBinary : Static ifs or specialization?

2020-06-23 Thread Meta via Digitalmars-d-learn

On Tuesday, 23 June 2020 at 23:53:36 UTC, claptrap wrote:
So you have opBinary and half a dozen operators to implement. 
Do you use a separate method for each operator or do you have 
one method and a big static if else if to select code path?


I assume they are functionally equivalent? So its just about 
style?


An idiomatic example:

import std.algorithm: among;

struct Test
{
int payload;

Test opBinary(string op)(Test other)
if (op.among!("+", "-", "*", "/")) //Limit supported ops
{
mixin("return Test(payload " ~ op ~ "other.val);");
}

int opBinary(string op)(int n)
//No constraint; support the full range of integer operations
{
mixin("return payload " ~ op ~ "n;");
}
}


Re: opBinary : Static ifs or specialization?

2020-06-23 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Jun 23, 2020 at 11:53:36PM +, claptrap via Digitalmars-d-learn 
wrote:
> So you have opBinary and half a dozen operators to implement. Do you
> use a separate method for each operator or do you have one method and
> a big static if else if to select code path?
[...]

If your implementations are based on built-in operators, you could use
mixins to unify the implementations into one, e.g.:

struct MyInt {
int i;
MyInt opBinary(string op)(MyInt arg) {
return MyInt(mixin("i "~op~" arg.i"));
}
}

which has far less boilerplate than separately implementing each
operator.  This is one of the main reasons for the design of .opBinary.


T

-- 
Let's eat some disquits while we format the biskettes.


opBinary : Static ifs or specialization?

2020-06-23 Thread claptrap via Digitalmars-d-learn
So you have opBinary and half a dozen operators to implement. Do 
you use a separate method for each operator or do you have one 
method and a big static if else if to select code path?


I assume they are functionally equivalent? So its just about 
style?


Re: Flagging special conditions on return from a function call

2020-06-23 Thread Paul Backus via Digitalmars-d-learn

On Tuesday, 23 June 2020 at 16:14:20 UTC, Denis wrote:
by presenting an interface that only compiles when both cases 
are covered, like fun().match((T t) => t, () => Error()).


A complete solution wrapped in a tidy package -- I like it.

Thanks for sharing.


If you're open to using Dub packages, I'd recommend sumtype [1] 
as an alternative to the standard-library Algebraic. It has much 
better compatibility with things like function attributes (@safe, 
nothrow, etc), mutability qualifiers, CTFE, and betterC, and also 
produces substantially more efficient code [2].


[1] https://code.dlang.org/packages/sumtype
[2] 
https://pbackus.github.io/blog/beating-stdvisit-without-really-trying.html


Web Assembly, struct to JavaScript Object and back

2020-06-23 Thread tirithen via Digitalmars-d-learn
I'm experimenting with generating wasm files with ldc2 but I'm 
having problems when trying to pass JavaScript Objects and 
receive them as structs and the other way around.


I found this super nice getting started guide that works fine for 
basic types like double and so on 
https://wiki.dlang.org/Generating_WebAssembly_with_LDC , but I'm 
puzzled on how to pass more advanced data structures.


I found this C example where it's mentioned that structs in that 
case will always be passed by pointer 
https://stackoverflow.com/questions/50615377/how-do-you-call-a-c-function-that-takes-or-returns-a-struct-by-value-from-js-v#answer-56405899 . Is something similar possible with D?


My setup so far:

test.d:

extern (C): // disable D mangling

void callback(double a, double b, double c);

double add(double a, double b) {
  const c = a + b;
  callback(a, b, c);
  return c;
}

struct Vector2 {
  double x;
  double y;
}

Vector2 addVectors(Vector2 a, Vector2 b) {
  return Vector2(a.x + b.x, a.y + b.y);
}

void _start() {
}

index.html:


  

  const callback = (a, b, c) => {
console.log(`callback from D: ${a} + ${b} = ${c}`);
  };

fetch('test.wasm').then((response) => response.arrayBuffer()).then((code) => {
const importObject = {env: {callback}};
WebAssembly.instantiate(code, importObject).then(result => {
  const {exports} = result.instance;

  const r = exports.add(42, -2.5);
  console.log('r = ' + r);

const r2 = exports.addVectors({x: 2, y: 4}, {x: 1, y: -1.5});
  console.log('r2 =', r2);
});
  });

  
  
Test page, open console to see the WASM results
  


Then I build test.d with:

$ ldc2 -mtriple=wasm32-unknown-unknown-wasm -L-allow-undefined 
-betterC test.d


When I serve and open the address in a browser and open the 
console I get:


r = 39.5
r2 = undefined

Anyone that has something similar working with struct objects?


Re: called copy constructor in foreach with ref on Range

2020-06-23 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/23/20 9:47 AM, Sebastiaan Koppe wrote:

On Tuesday, 23 June 2020 at 07:30:29 UTC, Stanislav Blinov wrote:

On Tuesday, 23 June 2020 at 05:24:37 UTC, H. S. Teoh wrote:
I'm also wondering what's the motivation behind supporting 
non-copyable ranges, and whether it's worth the effort and inevitable 
complications to support it if it's a rare use-case.
 Do you have any compelling use-case in mind, that might make this 
worthwhile?


This compelling use case is staring at us from comments in this very 
thread.


I am a bit on the fence about having input ranges be non-copyable. 
Initially I liked the idea very much; I am a big fan of 'unique' semantics.


But just because most people don't expect hot/destructive reads, doesn't 
mean we should impose such a hard restriction on input ranges. There are 
use cases for popping from an input range from different places. An 
obvious one would be parsing data from the network, where you pass the 
input range into helper functions that parse sub-sections of the data.


You can pass a reference if you need to, there's nothing wrong with that.


They can be made to work for sure, but it doesn't make it cleaner.

On the other hand, most of the time, non-copyable is exactly what you 
need...


Most of the time algorithms return rvalue ranges anyway, so move is not 
necessary. I think it would actually affect calls very little, and where 
it does affect them, you may find it actually fixes issues that you 
aren't aware of.


-Steve


Re: Flagging special conditions on return from a function call

2020-06-23 Thread Denis via Digitalmars-d-learn
Perhaps this thread would have been better titled "Returning a 
value and a status", and the question phrased as "What are your 
preferred techniques?".


I'm planning to port some of my programs to D, so I'd like to 
standardize on one or two techniques for handling this very 
common situation, in a way that suits the language. I'd 
appreciate hearing from others about what you do.


---

On Tuesday, 23 June 2020 at 06:52:29 UTC, Simen Kjærås wrote:

On Tuesday, 23 June 2020 at 04:01:45 UTC, Denis wrote:


[...]

(4) Set the function return value normally, and put the flag 
in an "out" variable passed as an argument to the function
(5) Return the flag, and put the value in an "out" variable 
passed to the function (i.e. the reverse of #4)


Both of these happen. I don't know which is more common. In C# 
these are probably the most common way (except for exceptions) 
to signal these cases.


Good to know. Both of these techniques (or something similar) are 
used in Perl too. The choice seemed to depend on which one the 
author thought would be more useful as the return.


[...]

by presenting an interface that only compiles when both cases 
are covered, like fun().match((T t) => t, () => Error()).


A complete solution wrapped in a tidy package -- I like it.

Thanks for sharing.


Re: are std.traits.FieldNameTuple and std.traits.Fields returned value always in sync?

2020-06-23 Thread mw via Digitalmars-d-learn

On Monday, 22 June 2020 at 20:08:37 UTC, Stanislav Blinov wrote:
But if you'd like it spelled out in text as well, you can make 
a PR for the Phobos repository.


Just-Did-It:

https://github.com/dlang/phobos/pull/7540


The point of doc is that the user don't have to dive into the 
code to know it's usage.


Re: called copy constructor in foreach with ref on Range

2020-06-23 Thread Paul Backus via Digitalmars-d-learn

On Tuesday, 23 June 2020 at 03:52:23 UTC, Jonathan M Davis wrote:


It is extremely common to wrap ranges in other ranges (and in 
fact, you basically have to in order to have lazy ranges). That 
really doesn't work very well - if at all - if you can't copy 
the range. It might be possible with a bunch of explicit calls 
to move, but that would result in range-based code in general 
being @system without a clean way to use @trusted


`move` isn't @system. Perhaps you are thinking of `moveEmplace`?




Re: called copy constructor in foreach with ref on Range

2020-06-23 Thread Sebastiaan Koppe via Digitalmars-d-learn

On Tuesday, 23 June 2020 at 07:30:29 UTC, Stanislav Blinov wrote:

On Tuesday, 23 June 2020 at 05:24:37 UTC, H. S. Teoh wrote:
I'm also wondering what's the motivation behind supporting 
non-copyable ranges, and whether it's worth the effort and 
inevitable complications to support it if it's a rare use-case.
 Do you have any compelling use-case in mind, that might make 
this worthwhile?


This compelling use case is staring at us from comments in this 
very thread.


I am a bit on the fence about having input ranges be 
non-copyable. Initially I liked the idea very much; I am a big 
fan of 'unique' semantics.


But just because most people don't expect hot/destructive reads, 
doesn't mean we should impose such a hard restriction on input 
ranges. There are use cases for popping from an input range from 
different places. An obvious one would be parsing data from the 
network, where you pass the input range into helper functions 
that parse sub-sections of the data.


They can be made to work for sure, but it doesn't make it cleaner.

On the other hand, most of the time, non-copyable is exactly what 
you need...


Re: opOpAssign of AA: defined behavior?

2020-06-23 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/23/20 5:15 AM, WebFreak001 wrote:

I have the following code:

     double[string] foo;
     foo["a"] += 1;

how is the opOpAssign on the AA defined? Is it defined to set the value 
to the value to the right of the opOpAssign if it isn't set for 
primitives or does it add the given value onto T.init?


Doing

     foo["b"]++;

gives me 1, so this looks like it comes from an arbitrary 0, however 
when I do


     double v = foo["c"]++;

I wanted to find out what initial value it is basing the increment off, 
however on dmd this triggered a segfault and on ldc this gave me 0. 
Where did the 0 come from? double.init should be NaN


I agree. I don't think it's defined by the language, but by the 
implementation.


Looking at the implementation, it's here: 
https://github.com/dlang/druntime/blob/2cc13ead1e7e535ef8ebd1f600d4ffb508a93f98/src/rt/aaA.d#L502-L577


Note the statement "[Returns:] If key was not in the aa, a mutable 
pointer to newly inserted value which is set to all zeros"


This is specifically where the zeroing happens: 
https://github.com/dlang/druntime/blob/2cc13ead1e7e535ef8ebd1f600d4ffb508a93f98/src/rt/aaA.d#L220


IIUC, this is a direct binding from the language, so we may not have the 
ability to set to init value in object.d, it would have to be done here.


-Steve


Re: opOpAssign of AA: defined behavior?

2020-06-23 Thread Eduard Staniloiu via Digitalmars-d-learn

On Tuesday, 23 June 2020 at 09:15:57 UTC, WebFreak001 wrote:

[...]

it will give me a range violation at runtime and not init it 
for me at all.


There is `aa.require("a", Foo.init) += 4;` now which solves 
this, but I would prefer having the small simple syntax well 
defined for all types instead of only primitives. Also I don't 
see anywhere in the specification that `require` must actually 
return a ref value, so I can't trust this either.


You make a very good case.

I think this would make a great bootcamp issue 
(https://issues.dlang.org/)


Cheers,
Edi



opOpAssign of AA: defined behavior?

2020-06-23 Thread WebFreak001 via Digitalmars-d-learn

I have the following code:

double[string] foo;
foo["a"] += 1;

how is the opOpAssign on the AA defined? Is it defined to set the 
value to the value to the right of the opOpAssign if it isn't set 
for primitives or does it add the given value onto T.init?


Doing

foo["b"]++;

gives me 1, so this looks like it comes from an arbitrary 0, 
however when I do


double v = foo["c"]++;

I wanted to find out what initial value it is basing the 
increment off, however on dmd this triggered a segfault and on 
ldc this gave me 0. Where did the 0 come from? double.init should 
be NaN


When I have a custom user defined type like

struct Foo
{
int x = 4;

ref Foo opOpAssign(string op : "+")(int v)
{
x += v;
return this;
}

Foo opBinary(string op : "+")(int v)
{
return Foo(x + v);
}
}

void main()
{
Foo[string] foo;
foo["a"] += 2;
writeln(foo);
}

it will give me a range violation at runtime and not init it for 
me at all.


There is `aa.require("a", Foo.init) += 4;` now which solves this, 
but I would prefer having the small simple syntax well defined 
for all types instead of only primitives. Also I don't see 
anywhere in the specification that `require` must actually return 
a ref value, so I can't trust this either.


Re: real.mant_dig on windows?

2020-06-23 Thread kinke via Digitalmars-d-learn

On Tuesday, 23 June 2020 at 02:56:36 UTC, 9il wrote:

Should it always be 53? or it can be 64, when?

Thank you


For LDC, it's 53 (and .sizeof == 8) for MSVC targets, but 64 
(x87) for MinGW, reflecting the accompanying C runtime's `long 
double`. [And IIRC, MS disallows any x87 usage in kernel code.]

For DMD, it's always 64, it only has x87 reals.


Re: called copy constructor in foreach with ref on Range

2020-06-23 Thread Stanislav Blinov via Digitalmars-d-learn

On Tuesday, 23 June 2020 at 05:24:37 UTC, H. S. Teoh wrote:
On Tue, Jun 23, 2020 at 03:25:55AM +, Stanislav Blinov via 
Digitalmars-d-learn wrote:
On Tuesday, 23 June 2020 at 02:41:55 UTC, Jonathan M Davis 
wrote:
> We'd need some major redesigning to make uncopyable ranges 
> work, and personally, I don't think that it's worth the 
> trouble.


Of course we would. Andrei is entertaining changing the whole 
input range API. Though he, like you, seems opposed to the 
idea of uncopyables.

[...]

I'm also wondering what's the motivation behind supporting 
non-copyable ranges, and whether it's worth the effort and 
inevitable complications to support it if it's a rare use-case.
 Do you have any compelling use-case in mind, that might make 
this worthwhile?


This compelling use case is staring at us from comments in this 
very thread. Like Jonathan said before - after you copied, you 
should only use the copy and not the original. Input range is a 
one-off iterable. You either consume it yourself, or give it away 
to someone else to consume. You can't do anything useful with it 
besides consuming it. But you can't give it away if it's copyable 
- you'd be giving someone a reference to mutable state which you 
also keep. Which brings about those very problems already talked 
about in this thread.  So if you "only should use the copy", well 
then duh, let's make it official and force you to write a move 
then (turning attempts to copy into compile errors)! Assuming, of 
course, that we do establish that .init must be an empty range. 
You'd be left with a valid state, callee would be given a valid 
state, neither of you would stomp on each other.


ByLine, just to become copyable, is made refcounted. It allocates 
its guts on the heap and molests an integer, all because it wants 
to remain copyable. But it is a call to "move" that is 
complication?


Or, perhaps, a complication would be partial consumption? E.g. 
chaining a take + map combo, but still wanting to consume 
remainder. That is solved by making wrapping ranges propagate the 
`source`, naturally, by moving it. Pretty straightforward.


Re: Flagging special conditions on return from a function call

2020-06-23 Thread Simen Kjærås via Digitalmars-d-learn

On Tuesday, 23 June 2020 at 04:01:45 UTC, Denis wrote:
(1) Assign an unused value for the flag (e.g. -1 when the 
function returns an int), and return the combined value/flag.


This happens in some Phobos algorithms, and might be the most 
common on this list.




(2) Return a tuple with the value and the flag
(3) Return a struct or tuple with named value and flag members


Would certainly work, but I don't think it's common in D.


(4) Set the function return value normally, and put the flag in 
an "out" variable passed as an argument to the function
(5) Return the flag, and put the value in an "out" variable 
passed to the function (i.e. the reverse of #4)


Both of these happen. I don't know which is more common. In C# 
these are probably the most common way (except for exceptions) to 
signal these cases.



(6) Use two separate functions, one that returns the value, and 
another that can be called afterwards to check the flag (like 
eof(), for example)




(7) Use a side effect and set a designated global variable


Global variables are frowned upon, so probably not this. :p


One thing I feel is missing here (perhaps because 
std.variant.Algebraic is egregious):


(8) Return a Maybe!T or Algebraic!(T, ErrorCode)

It's what I personally would prefer, but I have only rarely seen 
it in D code. Given a properly written Maybe, this could enforce 
proper handling of the error case, either by throwing on trying 
to get at Maybe!T.getValue when it's holding None, or by 
presenting an interface that only compiles when both cases are 
covered, like fun().match((T t) => t, () => Error()).


--
  Simen


Re: called copy constructor in foreach with ref on Range

2020-06-23 Thread Stanislav Blinov via Digitalmars-d-learn

On Tuesday, 23 June 2020 at 03:52:23 UTC, Jonathan M Davis wrote:
On Monday, June 22, 2020 9:25:55 PM MDT Stanislav Blinov via 
Digitalmars-d- learn wrote:
On Tuesday, 23 June 2020 at 02:41:55 UTC, Jonathan M Davis 
wrote:
> As things stand, uncopyable ranges aren't really a thing, 
> and common range idiomns rely on ranges being copyable.


Which idioms are those? I mean, genuine idioms, not design 
flaws like e.g. references.


It is extremely common to wrap ranges in other ranges (and in 
fact, you basically have to in order to have lazy ranges). That 
really doesn't work very well - if at all - if you can't copy 
the range. It might be possible with a bunch of explicit calls 
to move...


Where would "a bunch of explicit calls" come from???

See example implementations of map and filter here:
https://gist.github.com/radcapricorn/d76d29c6df6fa822d7889e799937f39d

If we disallow references as ranges, then any function that takes 
by value *owns that value*, and shouldn't needlessly copy it, 
only move. Yes, even when (in fact, especially when) that value 
is a mere wrapper over a pointer. Only when it would have to 
legitimately create a copy (i.e. fork the range) would it not 
move. At which point, if the range is non-copyable, it would be a 
compile error. Which would be a *good thing*.
That is what all generic code that works with values *should* be 
doing: moving, moving, moving. Copy ctors should only be called 
when *necessary*, not "meh, whenever".


Conceptually:

// assume OtherRange is a struct, which is what ranges should be
Range wrapRange(OtherRange)(OtherRange other)
{
// ...possibly pop some elements from `other`
return Range(other);
}

That's what Phobos is doing now. What's going on there? It makes 
a copy of `other` and then destructs `other`. There's no other 
use of `other`. So, it can simply (no, it *should*) just move 
`other`. Moving it would leave `other` in .init state, which is 
destructible, and construct Range with a valid value, without 
calling any copy ctors.
Walter's "moving, copying and forwarding" proposal, if it ever 
comes to fruition, would even let us drop the use of library 
moves in such cases.


...but that would result in range-based code in general being 
@system without a clean way to use @trusted, since


??? `move` infers.

whether it's really safe to mark such moves with @trusted would 
depend on the specific range implementation, which then is a 
big problem with generic code.


A one-argument `move` basically never should be inferred @system! 
(that is, if implementation isn't buggy, which it would seem it 
currently is in druntime...) Two-argument `move` might be 
@system, if the destructor is @system. Which means the range is 
@system anyway.


Regardless of whether it's actually possible to make it work 
though, it's a complete mess in comparison to simply copying.


And the fact that chaining range-based calls is extremely 
common makes the problem that much worse.


You mean this?

auto a = range.filter!foo.map!bar.array;

It's not a problem in any way. If `range` is non-copyable:

auto a = range.move.filter!foo.map!bar.array;

...which, if we do uphold the ".init is empty range" will *never* 
leave you with an invalid `range`, unlike copies that do 
who-knows-what.


The way that ranges are routinely passed around and wrapped 
works as well as it does, because ranges are copyable.


Now I see what you mean by "idioms". Copying things that 
shouldn't be copied :) Which is the bane of all Phobos.


The semantics of copying a variable or object vary wildly 
depending on the type regardless of whether we're talking about 
ranges. Copying a pointer or reference is still a copy even if 
it isn't a deep copy. Copying a range _always_ results in a 
copy, just like it does with any other type. It just doesn't 
necessarily result in a copy which can be independently 
iterated.


:) Which means:
- input ranges shouldn't be copyable -> no wild semantics 
anymore, statically enforced
- forward ranges should migrate save() into copy ctors -> 
guarantee a copy does what it should
- of course, .init must be an empty range, and all of this is 
moot so long as references are allowed to be ranges (all of this 
is one big "what if")


I feel like a broken record. Maybe I just should take that gist 
and make a more practical implementation out of it, as a demo 
(no, not with Andrei's `fetchNext`).