Re: Is there a cleaner way of doing this?

2017-08-12 Thread Mark via Digitalmars-d

On Saturday, 12 August 2017 at 15:02:34 UTC, Mark wrote:

I was going to suggest using Algebraic/Variant, as in:

void initialize(Algebraic!(int,void)) {


This should read:
  void initialize(Algebraic!(int,void) param) {




Re: Is there a cleaner way of doing this?

2017-08-12 Thread Mark via Digitalmars-d

On Monday, 7 August 2017 at 08:01:26 UTC, Shachar Shemesh wrote:
The problem is what happens when the param is optional. The 
common way to do this is to set T to void. This results in the 
following code:


struct S(T) {
enum HasParam = !is(T == void);
static if( HasParam ) {
T param;
}

static if( HasParam ) {
void initialize(T param) {
this.param = param;
// Other stuff
}
} else {
void initialize() {
// Same other stuff as above!
}
}
}

This is both tedious and error prone. Is there a cleaner way of 
doing this?


Shachar


I was going to suggest using Algebraic/Variant, as in:

void initialize(Algebraic!(int,void)) {
static if(hasParam)
this.param = param;
// Other stuff
}

but unfortunately Algebraic seems very cumbersome to use. You 
can't call initialize with an int (or "parameterlessly"); you 
have to use it like this:


x.initialize(Algebraic!(int,void)(my_integer)); //

which is bad in many ways, e.g. you'll have to import std.variant 
whenver you want to call initialize.


Ideally, I would have liked to write something like this:

void initialize( static if(hasParam) { mixin("T param"); } ) {
static if(hasParam) {
this.param = param;
}
// Other stuff
}

but of course this is currently not possible.


Re: Is there a cleaner way of doing this?

2017-08-08 Thread Andrei Alexandrescu via Digitalmars-d

On 08/08/2017 05:03 AM, Timon Gehr wrote:

On 08.08.2017 08:06, Shachar Shemesh wrote:

On 07/08/17 12:37, Timon Gehr wrote:


struct S(T...) {
 T param;

 void initialize(T param) {
 this.param = param;
 // Other stuff
 }
}

Then, use S!() instead of S!void.



It's an interesting approach. It has the down side that it also 
accepts S!(int, string, int[23], double), and I'm still not sure what 
I think about this option (i.e. - whether I want to allow it).


If not, then things start to look quite misleading to the user, and 
I'd rather have the ugly static-ifs than do that.


Shachar


I don't see why not, but you can just add a template constraint:

struct S(T...) if(T.length<=1) { ... }


You can also hide the approach as an implementation detail:

struct S(T){
 static if(is(T==void)){
 private alias X = AliasSeq!();
 }else{
 private alias X = AliasSeq!T;
 }
 X param;
 void initialize(X param){
 this.param=param;
 // ...
 }
}


Very good creative use of the language, kudos Timon. -- Andrei


Re: Is there a cleaner way of doing this?

2017-08-08 Thread Timon Gehr via Digitalmars-d

On 08.08.2017 08:06, Shachar Shemesh wrote:

On 07/08/17 12:37, Timon Gehr wrote:


struct S(T...) {
 T param;

 void initialize(T param) {
 this.param = param;
 // Other stuff
 }
}

Then, use S!() instead of S!void.



It's an interesting approach. It has the down side that it also accepts 
S!(int, string, int[23], double), and I'm still not sure what I think 
about this option (i.e. - whether I want to allow it).


If not, then things start to look quite misleading to the user, and I'd 
rather have the ugly static-ifs than do that.


Shachar


I don't see why not, but you can just add a template constraint:

struct S(T...) if(T.length<=1) { ... }


You can also hide the approach as an implementation detail:

struct S(T){
static if(is(T==void)){
private alias X = AliasSeq!();
}else{
private alias X = AliasSeq!T;
}
X param;
void initialize(X param){
this.param=param;
// ...
}
}


Re: Is there a cleaner way of doing this?

2017-08-08 Thread Shachar Shemesh via Digitalmars-d

On 07/08/17 12:37, Timon Gehr wrote:


struct S(T...) {
 T param;

 void initialize(T param) {
 this.param = param;
 // Other stuff
 }
}

Then, use S!() instead of S!void.



It's an interesting approach. It has the down side that it also accepts 
S!(int, string, int[23], double), and I'm still not sure what I think 
about this option (i.e. - whether I want to allow it).


If not, then things start to look quite misleading to the user, and I'd 
rather have the ugly static-ifs than do that.


Shachar


Re: Is there a cleaner way of doing this?

2017-08-07 Thread Dgame via Digitalmars-d

On Monday, 7 August 2017 at 08:01:26 UTC, Shachar Shemesh wrote:
It is often desired to have a struct with an extra parameter. 
The common way to do this is like so:


struct S(T) {
T param;

void initialize(T param) {
this.param = param;
// Other stuff
}
}

The problem is what happens when the param is optional. The 
common way to do this is to set T to void. This results in the 
following code:


struct S(T) {
enum HasParam = !is(T == void);
static if( HasParam ) {
T param;
}

static if( HasParam ) {
void initialize(T param) {
this.param = param;
// Other stuff
}
} else {
void initialize() {
// Same other stuff as above!
}
}
}

This is both tedious and error prone. Is there a cleaner way of 
doing this?


Just as an unrealistic fantasy, if the following code was 
legal, the problem would be resolved on its own:

void func(void p) {
void param;

param = p;

return param;
}


Of course, that code has its own set of problems, and I'm not 
really suggesting that change.


Shachar


Why don't you use a factory method?

struct S(T)
{
T p;

static make(T p)
{
S s;
s.p = p;

return s;
}

static make()
{
return S();
}
}

void main()
{
auto s1 = S!int.make;
auto s2 = S!string.make;
}


Re: Is there a cleaner way of doing this?

2017-08-07 Thread Diego via Digitalmars-d

On Monday, 7 August 2017 at 08:01:26 UTC, Shachar Shemesh wrote:
It is often desired to have a struct with an extra parameter. 
The common way to do this is like so:


struct S(T) {
T param;

void initialize(T param) {
this.param = param;
// Other stuff
}
}

The problem is what happens when the param is optional. The 
common way to do this is to set T to void. This results in the 
following code:


struct S(T) {
enum HasParam = !is(T == void);
static if( HasParam ) {
T param;
}

static if( HasParam ) {
void initialize(T param) {
this.param = param;
// Other stuff
}
} else {
void initialize() {
// Same other stuff as above!
}
}
}

This is both tedious and error prone. Is there a cleaner way of 
doing this?


Just as an unrealistic fantasy, if the following code was 
legal, the problem would be resolved on its own:

void func(void p) {
void param;

param = p;

return param;
}


Of course, that code has its own set of problems, and I'm not 
really suggesting that change.


Shachar


You can use type default initialization property:

struct S(T) {
T param;

void initialize(T param = T.init) {
this.param = param;
// Other stuff
}
}

S!int s;
s.initialize(42);  // works
s.initialize();  // also works; s.param == int.init == 0




Re: Is there a cleaner way of doing this?

2017-08-07 Thread Timon Gehr via Digitalmars-d

On 07.08.2017 10:01, Shachar Shemesh wrote:
It is often desired to have a struct with an extra parameter. The common 
way to do this is like so:


struct S(T) {
 T param;

 void initialize(T param) {
 this.param = param;
 // Other stuff
 }
}

The problem is what happens when the param is optional. The common way 
to do this is to set T to void. This results in the following code:


struct S(T) {
 enum HasParam = !is(T == void);
 static if( HasParam ) {
 T param;
 }

 static if( HasParam ) {
 void initialize(T param) {
 this.param = param;
 // Other stuff
 }
 } else {
 void initialize() {
 // Same other stuff as above!
 }
 }
}

This is both tedious and error prone. Is there a cleaner way of doing this?
...


struct S(T...) {
T param;

void initialize(T param) {
this.param = param;
// Other stuff
}
}

Then, use S!() instead of S!void.

Just as an unrealistic fantasy, if the following code was legal, the 
problem would be resolved on its own:

void func(void p) {
 void param;

 param = p;

 return param;
}


Of course, that code has its own set of problems, and I'm not really 
suggesting that change.


Shachar


The only reason this code is problematic is that void.sizeof == 1.


Re: Is there a cleaner way of doing this?

2017-08-07 Thread Ali Çehreli via Digitalmars-d

On 08/07/2017 01:01 AM, Shachar Shemesh wrote:

It is often desired to have a struct with an extra parameter. The common
way to do this is like so:

struct S(T) {
T param;

void initialize(T param) {
this.param = param;
// Other stuff
}
}

The problem is what happens when the param is optional. The common way
to do this is to set T to void. This results in the following code:

struct S(T) {
enum HasParam = !is(T == void);
static if( HasParam ) {
T param;
}

static if( HasParam ) {
void initialize(T param) {
this.param = param;
// Other stuff
}
} else {
void initialize() {
// Same other stuff as above!
}
}
}

This is both tedious and error prone. Is there a cleaner way of doing this?


A mixin template can work. The whole param-related code is in one place 
and the void specialization obviates the need for static if:


mixin template ParamCode(T) {
T param;

void initializeParam(T param) {
this.param = param;
initialize();
}
}

template ParamCode(T : void) {
}

struct S(T) {
mixin ParamCode!T;

void initialize() {
// ...
}
}

unittest {
auto a = S!int();
static assert(a.sizeof == int.sizeof);
a.initializeParam(42);

auto b = S!void();
static assert(b.sizeof == 1);
b.initialize();
}

void main() {
}

Ali