Re: Input/Output multiple values from function

2019-09-02 Thread Ali Çehreli via Digitalmars-d-learn

On 08/27/2019 10:17 PM, Jabari Zakiya wrote:

> I can't do (a, b, c,d) = func1(i) directly.
> What do I do to assign the output of func1 to the individual variables?

I had some time to play with the following syntax, similar usage of 
which has been proposed a number of times as a replacement for tuple 
expansion. Assuming that foo() returns a struct of int, double, string; 
the following expression will set the variables to those members:


  int i;
  double d;
  string s;

  foo(42).into!(i, d, s);

Here is the complete program:

import std.stdio;
import std.string;

struct S {
  int i;
  double d;
  string s;
}

S foo(int i) {
  return S(i, 1.5, "hi");
}

template into(args...) {
  auto into(From)(From from)
  if (is (From == struct))
  {
static foreach (i, m; __traits(allMembers, From)) {{
  alias argT = typeof(args[i]);
  alias memT = typeof(__traits(getMember, from, m));
  static assert (is (argT == memT),
 format!"Cannot expand '%s %s.%s' into '%s %s' 
argument."
 (memT.stringof, From.stringof, m, argT.stringof, 
args[i].stringof));

  mixin (format!"args[%s] = from.%s;"(i, m));
}}
  }
}

void main() {
  int i;
  double d;
  string s;

  foo(42).into!(i, d, s);

  writeln(i);
  writeln(d);
  writeln(s);
}

I know that it does not address attributes like shared, etc. but it 
shows how expressive nested templates can be.


Ali



Re: Input/Output multiple values from function

2019-09-02 Thread Jabari Zakiya via Digitalmars-d-learn

On Sunday, 1 September 2019 at 20:50:42 UTC, Paul Backus wrote:
On Sunday, 1 September 2019 at 20:42:28 UTC, Jabari Zakiya 
wrote:

It still won't compile, with this error.

Error: AliasSeq!(modpg, res_0, restwins, resinvrs) is not an 
lvalue and cannot be modified


Here's a gist of the code.

Top functions in code with issues are genPgParameters and 
selectPG


https://gist.github.com/jzakiya/9227e4810e1bd5b4b31e949d1cbd5c5d


You can't do multiple assignments at once using AliasSeq; you 
have to assign each variable individually:


auto parameters = genPgParameters(pg);
modpg = parameters[0];
res_0 = parameters[1];
restwins = parameters[2];
resinvrs = parameters[3];


There's still are problem When I do this.

auto parameters = genPgParameters(pg);
  modpg = parameters[0];
  res_0 = parameters[1];
  restwins = parameters[2];
  resinvrs = parameters[3];

The compiler says this:

Error: cannot implicitly convert expression 
parameters.__expand_field_3 of type uint[] to shared(uint[])


If I comment out the last line the programs compiles (and crashes 
when run since all the parameters aren't available).


So why does it accept parameter[2] but not [3] as they are both 
defined the same?


Is this a compiler bug?

I have to say, getting this simple parameter passing to work in D 
has been an infuriating experience. :-(


Re: Input/Output multiple values from function

2019-09-01 Thread Paul Backus via Digitalmars-d-learn

On Sunday, 1 September 2019 at 20:42:28 UTC, Jabari Zakiya wrote:

It still won't compile, with this error.

Error: AliasSeq!(modpg, res_0, restwins, resinvrs) is not an 
lvalue and cannot be modified


Here's a gist of the code.

Top functions in code with issues are genPgParameters and 
selectPG


https://gist.github.com/jzakiya/9227e4810e1bd5b4b31e949d1cbd5c5d


You can't do multiple assignments at once using AliasSeq; you 
have to assign each variable individually:


auto parameters = genPgParameters(pg);
modpg = parameters[0];
res_0 = parameters[1];
restwins = parameters[2];
resinvrs = parameters[3];


Re: Input/Output multiple values from function

2019-09-01 Thread Jabari Zakiya via Digitalmars-d-learn

On Thursday, 29 August 2019 at 10:58:47 UTC, Simen Kjærås wrote:
On Thursday, 29 August 2019 at 10:39:44 UTC, Jabari Zakiya 
wrote:

[...]


Great - then you can use shared(immutable(uint)[]). You should 
be able to convert from immutable(uint[]) to that without 
issue. There's a utility function in std.exception called 
assumeUnique that can be used for conversion to immutable that 
may be more informative than cast(immutable):


shared(uint) modpg;
shared(uint) res_0;
shared(immutable(uint)[]) restwins;
shared(immutable(uint)[]) resinvrs;

auto genPGparameters(int i) {
import std.typecons;
import std.exception;
// Showing both cast and assumeUnique:
return tuple(1u, 2u, cast(immutable)[3u], 
[4u].assumeUnique);

}

unittest {
import std.meta : AliasSeq;
int pg;
// No need for temporaries:
AliasSeq!(modpg, res_0, restwins, resinvrs) = 
genPGparameters(pg);

}



[...]


Correct - since there are no indirections in a uint, you can 
assign directly to a shared(uint) - nobody else will have a 
non-shared pointer to that uint, so it's somewhat safe. If you 
do the same with uint[], you'll still have a pointer to the 
same values, and changing a value that says it's thread-local 
(no shared) will change values that is shared with the rest of 
the program. There are some issues with the current shared 
design, but this is what it's intended to do.


--
  Simen


It still won't compile, with this error.

Error: AliasSeq!(modpg, res_0, restwins, resinvrs) is not an 
lvalue and cannot be modified


Here's a gist of the code.

Top functions in code with issues are genPgParameters and selectPG

https://gist.github.com/jzakiya/9227e4810e1bd5b4b31e949d1cbd5c5d


Re: Input/Output multiple values from function

2019-08-29 Thread Simen Kjærås via Digitalmars-d-learn

On Thursday, 29 August 2019 at 10:39:44 UTC, Jabari Zakiya wrote:
The values modpg, res_0, restwins, and resinvrs are constant 
(immutable) values that are generated at run time. They are 
global/shared and used inside threads.


So this process is initializing them at the start of the 
program, based on the input values to it.


Great - then you can use shared(immutable(uint)[]). You should be 
able to convert from immutable(uint[]) to that without issue. 
There's a utility function in std.exception called assumeUnique 
that can be used for conversion to immutable that may be more 
informative than cast(immutable):


shared(uint) modpg;
shared(uint) res_0;
shared(immutable(uint)[]) restwins;
shared(immutable(uint)[]) resinvrs;

auto genPGparameters(int i) {
import std.typecons;
import std.exception;
// Showing both cast and assumeUnique:
return tuple(1u, 2u, cast(immutable)[3u], [4u].assumeUnique);
}

unittest {
import std.meta : AliasSeq;
int pg;
// No need for temporaries:
AliasSeq!(modpg, res_0, restwins, resinvrs) = 
genPGparameters(pg);

}


The compiler only has a problem, it seems, with the arrays and 
not the single values.


Correct - since there are no indirections in a uint, you can 
assign directly to a shared(uint) - nobody else will have a 
non-shared pointer to that uint, so it's somewhat safe. If you do 
the same with uint[], you'll still have a pointer to the same 
values, and changing a value that says it's thread-local (no 
shared) will change values that is shared with the rest of the 
program. There are some issues with the current shared design, 
but this is what it's intended to do.


--
  Simen


Re: Input/Output multiple values from function

2019-08-29 Thread Jabari Zakiya via Digitalmars-d-learn

On Thursday, 29 August 2019 at 09:04:17 UTC, Simen Kjærås wrote:
On Wednesday, 28 August 2019 at 13:11:46 UTC, Jabari Zakiya 
wrote:

[...]


Reduced example:

unittest {
int[] a;
// cannot implicitly convert expression a of type int[] to 
shared(int[])

shared int[] b = a;
}

This is because an int[] is mutable and thread-local, while 
shared(int[]) is mutable and shared. Shared mutable data must 
be guarded closely, preferably behind a mutex or similar. 
Assigning the value of `a` to `b` above would leave a mutable 
reference to the shared data on a thread, and could easily lead 
to race conditions.


In order to fix this issue, consider several things:

Do modpg and friends really need to be shared? Removing 
shared() from them will still make them available to other 
parts of your code, but they will be thread-local instead. If 
you're not doing threaded work, that should be perfectly fine.


Can they be immutable? If they're initialized once and never 
changed, this could be a good solution.


If they need to be shared and mutable, have you protected them 
enough from race conditions? Are there possible situations 
where other threads may be accessing them while one thread is 
writing to them?


Multi-threaded programming is hard, and requires a lot more 
knowledge than we have about your project from the code you've 
posted, so only you can answer these questions. If you're 
unsure, you can probably just remove shared() from modpg and 
friends.


--
  Simen


The values modpg, res_0, restwins, and resinvrs are constant 
(immutable) values that are generated at run time. They are 
global/shared and used inside threads.


So this process is initializing them at the start of the program, 
based on the input values to it.


The compiler only has a problem, it seems, with the arrays and 
not the single values.


Re: Input/Output multiple values from function

2019-08-29 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 28 August 2019 at 13:11:46 UTC, Jabari Zakiya wrote:

When I do this:

uint a; uint b; uint[] c; uint[] d;
  AliasSeq!(a, b, c, d) = genPGparameters(pg);
  modpg= a;
  res_0= b;
  restwins = c;
  resinvrs = d;

the compiler (ldc2 1.17) says:

D Projects ~/D/bin/ldc2 --release -O3 twinprimes_ssoznew1.d
twinprimes_ssoznew1.d(170): Error: cannot implicitly convert 
expression c of type uint[] to shared(uint[])
twinprimes_ssoznew1.d(171): Error: cannot implicitly convert 
expression d of type uint[] to shared(uint[])


where modpg, res_0; restwins, resinvrs are shared (global) 
variables.


Reduced example:

unittest {
int[] a;
// cannot implicitly convert expression a of type int[] to 
shared(int[])

shared int[] b = a;
}

This is because an int[] is mutable and thread-local, while 
shared(int[]) is mutable and shared. Shared mutable data must be 
guarded closely, preferably behind a mutex or similar. Assigning 
the value of `a` to `b` above would leave a mutable reference to 
the shared data on a thread, and could easily lead to race 
conditions.


In order to fix this issue, consider several things:

Do modpg and friends really need to be shared? Removing shared() 
from them will still make them available to other parts of your 
code, but they will be thread-local instead. If you're not doing 
threaded work, that should be perfectly fine.


Can they be immutable? If they're initialized once and never 
changed, this could be a good solution.


If they need to be shared and mutable, have you protected them 
enough from race conditions? Are there possible situations where 
other threads may be accessing them while one thread is writing 
to them?


Multi-threaded programming is hard, and requires a lot more 
knowledge than we have about your project from the code you've 
posted, so only you can answer these questions. If you're unsure, 
you can probably just remove shared() from modpg and friends.


--
  Simen


Re: Input/Output multiple values from function

2019-08-28 Thread Jabari Zakiya via Digitalmars-d-learn

On Wednesday, 28 August 2019 at 10:10:08 UTC, Simen Kjærås wrote:
On Wednesday, 28 August 2019 at 05:17:28 UTC, Jabari Zakiya 
wrote:
Inside func2 I create an input value for func1 and then assign 
func1's 4 outputs to named variable. That's where the problems 
arise. func1 does some math based on the input and generates 4 
outputs.


I can't do (a, b, c,d) = func1(i) directly.
What do I do to assign the output of func1 to the individual 
variables?


import std.meta : AliasSeq;
import std.typecons : tuple;

auto fun() {
return tuple(1, "test");
}

unittest {
int a;
string b;
AliasSeq!(a, b) = fun;
assert(a == 1);
assert(b == "test");
}

--
  Simen


When I do this:

uint a; uint b; uint[] c; uint[] d;
  AliasSeq!(a, b, c, d) = genPGparameters(pg);
  modpg= a;
  res_0= b;
  restwins = c;
  resinvrs = d;

the compiler (ldc2 1.17) says:

D Projects ~/D/bin/ldc2 --release -O3 twinprimes_ssoznew1.d
twinprimes_ssoznew1.d(170): Error: cannot implicitly convert 
expression c of type uint[] to shared(uint[])
twinprimes_ssoznew1.d(171): Error: cannot implicitly convert 
expression d of type uint[] to shared(uint[])


where modpg, res_0; restwins, resinvrs are shared (global) 
variables.




Re: Input/Output multiple values from function

2019-08-28 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 28 August 2019 at 05:17:28 UTC, Jabari Zakiya wrote:
Inside func2 I create an input value for func1 and then assign 
func1's 4 outputs to named variable. That's where the problems 
arise. func1 does some math based on the input and generates 4 
outputs.


I can't do (a, b, c,d) = func1(i) directly.
What do I do to assign the output of func1 to the individual 
variables?


import std.meta : AliasSeq;
import std.typecons : tuple;

auto fun() {
return tuple(1, "test");
}

unittest {
int a;
string b;
AliasSeq!(a, b) = fun;
assert(a == 1);
assert(b == "test");
}

--
  Simen


Re: Input/Output multiple values from function

2019-08-28 Thread a11e99z via Digitalmars-d-learn

On Wednesday, 28 August 2019 at 05:17:28 UTC, Jabari Zakiya wrote:

On Wednesday, 28 August 2019 at 04:39:23 UTC, Mike Parker wrote:
On Wednesday, 28 August 2019 at 04:19:49 UTC, Jabari Zakiya 
wrote:
I have a function (say func1) that takes 1 input value (an 
integer number) and outputs 4 values (2 integers and 2 arrays 
of integers).


Then inside another function (say func2) I provide the 1 
input to func1 and then want to assign its 4 output values to 
their appropriate final variables that will use them.




https://dlang.org/library/std/typecons/tuple.expand.html ?



Re: Input/Output multiple values from function

2019-08-27 Thread Jabari Zakiya via Digitalmars-d-learn

On Wednesday, 28 August 2019 at 04:39:23 UTC, Mike Parker wrote:
On Wednesday, 28 August 2019 at 04:19:49 UTC, Jabari Zakiya 
wrote:
I have a function (say func1) that takes 1 input value (an 
integer number) and outputs 4 values (2 integers and 2 arrays 
of integers).


Then inside another function (say func2) I provide the 1 input 
to func1 and then want to assign its 4 output values to their 
appropriate final variables that will use them.


Conceptually I want to do below:

func2 { ...; (a, b, c, d) = func1(i) }

I tried using a struct but compiler keeps complaining.

Thanks for help in advance.


A struct should work just fine:

https://run.dlang.io/is/aMBGD0

import std.stdio;
struct Results {
int a, b;
int[] aa, ab;
}

Results func1() {
return Results(1, 2, [0, 1, 2, 3], [10, 11, 12]);
}

void main()
{
writeln(func1);
}

What is the compiler complaining about?


Inside func2 I create an input value for func1 and then assign 
func1's 4 outputs to named variable. That's where the problems 
arise. func1 does some math based on the input and generates 4 
outputs.


I can't do (a, b, c,d) = func1(i) directly.
What do I do to assign the output of func1 to the individual 
variables?




Re: Input/Output multiple values from function

2019-08-27 Thread Mike Parker via Digitalmars-d-learn

On Wednesday, 28 August 2019 at 04:19:49 UTC, Jabari Zakiya wrote:
I have a function (say func1) that takes 1 input value (an 
integer number) and outputs 4 values (2 integers and 2 arrays 
of integers).


Then inside another function (say func2) I provide the 1 input 
to func1 and then want to assign its 4 output values to their 
appropriate final variables that will use them.


Conceptually I want to do below:

func2 { ...; (a, b, c, d) = func1(i) }

I tried using a struct but compiler keeps complaining.

Thanks for help in advance.


A struct should work just fine:

https://run.dlang.io/is/aMBGD0

import std.stdio;
struct Results {
int a, b;
int[] aa, ab;
}

Results func1() {
return Results(1, 2, [0, 1, 2, 3], [10, 11, 12]);
}

void main()
{
writeln(func1);
}

What is the compiler complaining about?