Runtime error trying to call opCall on variant array of objects

2016-12-24 Thread aliak via Digitalmars-d-learn
Hey, so I'm trying to make an variant array of objects (each one 
has an opCall defined) and then call each of them in succession. 
It doesn't seem to be working. The error I get is:


"Cannot apply `()' to a value of type `Command!(__lambda1, int)". 
I think it's failing when it checks for "!isFunctionPointer!A && 
!isDelegate!A".


Here's the bit of code:

struct Command(alias fun, Args...) {
Args args;
this(Args args) {
args = args;
}
auto opCall() {
return fun(args);
}
}

auto command(alias fun, Args...)(Args args) {
return Command!(fun, Args)(args);
}

void main() {
auto commands = variantArray(
command!(a => a + 1)(1),
command!(a => a + 2)(1),
command!(a => a + 3)(1),
);

   // commands.each!(a => a()); // <-- crashes runtime

typeid(commands[0]).writeln; // 
std.variant.VariantN!32LU.VariantN


auto cmd = command!(a => a + 1)(1);
typeid(cmd).writeln; // scratchpad.main.Command!(__lambda4, 
int).Command

}

Is there a way to do what I'm trying to do?

Cheers!


Re: Is there anything other than nullable to work with optional types?

2016-12-26 Thread aliak via Digitalmars-d-learn

On Monday, 26 December 2016 at 04:55:30 UTC, Seb wrote:

Then help to push it forward!!
There are many ways:
- review the PR and point out anything problematic you see 
(lack of reviews/interest  is a main reason why PRs get stalled)
- post reasons and arguments for merging this PR (seems like 
you have a couple of good real world examples - post them!)
- revive the PR (it's quite old and the author probably lost 
interest. There's absolutely nothing wrong with taking the diff 
and resubmitting it - on the contrary that's often the only 
possible way to revive/save old PRs)

...


Sure, will take a gander. Might try and revive if I feel up to it 
after reading through but I don't think I'm comfortable enough 
with D yet to do that. But lets see.




Re: Runtime error trying to call opCall on variant array of objects

2016-12-25 Thread aliak via Digitalmars-d-learn

On Saturday, 24 December 2016 at 23:06:25 UTC, Ali Çehreli wrote:

auto c = Command!(fun, Args)(args);
writefln("Created %s", c);
// (3) Workaround: Storing delegates, not Command instances.
return () => c();


Ah, yes. Nice work around :)

Thankies!


Re: Is there anything other than nullable to work with optional types?

2016-12-25 Thread aliak via Digitalmars-d-learn

On Sunday, 25 December 2016 at 20:11:50 UTC, Seb wrote:

On Sunday, 25 December 2016 at 19:22:10 UTC, aliak wrote:

or is there a way for it to not be so cumbersome to work with?



You might be interested in

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


Yes! That!

Seems like that PR is on a break though :(


Is there anything other than nullable to work with optional types?

2016-12-25 Thread aliak via Digitalmars-d-learn

Hey,

So, been using the programming language swift for a while now, 
the optional types[1] they support makes working with maybe-type 
(ala haskell) values extremely pleasant.


Does D have anything other than the Nullable template that can be 
used to work with optionals, or is there a way for it to not be 
so cumbersome to work with?


Eg: Currently I have a function like this:

struct MarkerData {
long start;
long end;
long length;
long times;
}

Nullable!MarkerData pluckMarker(string str) {
auto start = str.indexOf("(");
if (start == -1) {
return typeof(return).init;
}
auto end = str.indexOf(")", start);
if (end == -1) {
return typeof(return).init;
}
auto parts = str[start+1..end].split("x");
auto length = to!long(parts[0]);
auto times = to!long(parts[1]);
return Nullable!MarkerData(MarkerData(start, end, length, 
times));

}

Everywhere I have to return the Nullable! type, I have to either 
use that typeof(return).init to make it a null value, or a quite 
verbose constructor call to return a concrete type.


Can it be made simpler to use without me having to alias 
Nullable!MarkerData (which still wouldn't help with just 
returning null).


[1] will try a super quick explanation of optional types. You 
basically add a '?' to any type declaration and then it's 
nullable. And you can implicitly assign nil and also the concrete 
type.


Re: Halp! type system (__expand_field_0 error), compile time/runtime questions (AoC-2017 puzzle spoilers inside)

2017-12-14 Thread aliak via Digitalmars-d-learn

On Thursday, 14 December 2017 at 15:28:22 UTC, aliak wrote:

  int[] rotate(int[] list, int[] lengths) {
auto range = list.cycle;
foreach (skip, length; lengths.enumerate) {
  //  do stuff to range
}
return list;
  }


Ok srsly, I got things to at least compile by changing the above 
rotate function to use a for loop instead lengths.enumerate:


  int[] rotate(int[] list, int[] lengths) {
auto range = list.cycle;
for (int skip = 0; skip < lengths.length; ++skip) {
 // do stuff to range
}
return list;
  }

uhh ... ??


Halp! type system (__expand_field_0 error), compile time/runtime questions (AoC-2017 puzzle spoilers inside)

2017-12-14 Thread aliak via Digitalmars-d-learn
Warning: following has Advent of Code 2017 (day 14 and day 10) 
spoilers incase you are doing those challenges. And apologies for 
the slightly long post, I'm unsure how much information is needed 
here and am a bit clueless. Any help would be much appreciated.


=

Ok, so I'm trying to get through these daily code puzzles with D. 
Most of my troubles so far have come from trying to coax the type 
system in to behaving how I want/expect, and parsing input data 
at compile time. My background is a fair amount of C++ in the 
past, and these days Swift (just incase it helps with explaining 
things)


(fun little tidbit, we're a decent size group at work doing these 
challenges in many languages and D is usually second in 
performance after C! :) - other contenders include python, go, 
scala, scheme, elixr, elm, javascript, fortran(!), kotlin, and 
quite a few more - one nut job actually decided to do a different 
language every day this month)


So for executing each of these puzzles (they all have two parts) 
I have the following setup:


app.d:

  import _day14;
  enum data = process(import("day14.txt")); // load input file
  void main() { solveA(data); solveB(data) }

So input processing is compile time, and solutions are executed 
at runtime (i think?). Today's problem involves a custom hash 
function that was developed on day 10 of the calendar.


So in my "_14.d" file I have this at the top:

  // takes a string, hashes it and returns 32 character hex string
  module _14;
  import _10: knotHashHex = solveB;

Today's problem requires this hex string to be converted in to 
binary (i.e. each hex char to 4 binary chars) - I am aware that 
an optimization here would be to use bits instead of chars but 
meh :p. So I have this defined:


  // Takes "af49cb351fa..." -> "0010010111011..."
  alias knotHash = (string input)
=> knotHashHex(input)
.map!binary // converts a dchar to a binary string so 'f' 
-> ""

.join;

So my app first calls "process" on the input data (which is a 
random string for today) and then the output of that goes in to 
solveA and solveB of my day14 module. My "process" function for 
today is this:


  // size "immutable size = 128;"
  // The puzzle requires a 128x128 grid of 1's and 0's so we 
reuse the input string

  //   each round and just append a "-i" to it.
  auto process(string input) {
return size
.iota
.map!(i => input ~ "-" ~ i.text)
.array
.map!knotHash
  }

So the output type of this function is:
  MapResult!(function (string input) => join(map(solveB(input))), 
string[])


My solveA part works fine, you're supposed to count the number of 
1's in the grid so it's a simple:


  auto solveA(ReturnType!process grid) {
return grid
.join
.count!q{a == '1'};
  }

The next part is where I start to have problems. It involves a 
recursive depth-first-search approach so I have a function that 
recurses:


  void visit(ref string[] grid, int i, int j, ref 
bool[size][size] visited) {

// check stuff and call visit again
  }

And my solveB looks like this:

  auto solveB(ReturnType!process grid) {
auto arrayGrid = grid.array; // convert to string[]
// more code then at some point I call:
visit(arrayGrid, i, j, visited);
  }

So up to here everything works. But now I don't like that I have 
a "grid.array" inside solveB but not in solveA. Seems 
asymmetrical. So I figured I could just change my "process" 
function above to return an array directly by just adding a 
".array" to the pipeline.


Then I get this error:

  Error: couldn't find field __expand_field_0 of type ulong in 
Tuple(0LU, 117)


117 is the ascii code for 'u' btw, which happens to be the first 
character in my random input string. This error is coming from 
inside my day 10's "solveB" function (which is imported in day 14 
as "knotHashHex"). It comes from here:


  int[] rotate(int[] list, int[] lengths) {
auto range = list.cycle;
foreach (skip, length; lengths.enumerate) { // <-- here is 
error

  //  do stuff to range
}
return list;
  }

So it says something about ulong and expanding a tuple type. But 
I'm having a hard time with this error message.


Questions: What does it mean? It can't expand field 0 (the ulong) 
in to my skip variable? Why not? And most importantly, why is it 
having trouble here during my "process" function, but not 
screaming when I call "grid.array" in my "solveB" function? What 
am I doing wrong?


So anyway, Halp!




Re: Halp! type system (__expand_field_0 error), compile time/runtime questions (AoC-2017 puzzle spoilers inside)

2017-12-14 Thread aliak via Digitalmars-d-learn
On Thursday, 14 December 2017 at 16:38:26 UTC, Steven 
Schveighoffer wrote:
So enumerate returns as its element type a Tuple. Specifically, 
it's going to be a Tuple!(size_t, int), since you are 
enumerating an array of ints.


I'm not sure why you are having the error, compiling your code 
above works perfectly fine for me. It would help to know:


a) which version of the compiler you are using?


Tried with dmd v2.077.1. Also with LDC 1.6 (which uses dmd 
v2.076.1)


b) if the above actually does compile for you, what is the 
minimal code that does not?


Yes of course, here's a minimal program that does not compile for 
me:


  import std.stdio, std.algorithm, std.range, std.array;

  int rotate(int[] lengths) {
foreach(skip, length; lengths.enumerate) {}
return 0;
  }

  auto knotHash(string input) {
return [1].rotate();
  }

  auto data = ["string"]
.map!knotHash
.array;

  void main() {}


The above code, however, will compile with any of the following 
changes, and I don't understand why for any of them:

1) remove .enumerate
2) move the auto data inside the body of main
3) remove the call to .array


All that aside, you may not realize, this works as well:

foreach(skip, length; lengths)


Sweet, thanks! Yeah that works too.

Another thing I realized is that if I switch from .enumerate to 
the foreach you suggest (in my non minimized example) the compile 
time increases by A LOT. From about 1 second to 70 seconds.





Re: Halp! type system (__expand_field_0 error), compile time/runtime questions (AoC-2017 puzzle spoilers inside)

2017-12-15 Thread aliak via Digitalmars-d-learn
On Friday, 15 December 2017 at 01:43:04 UTC, Steven Schveighoffer 
wrote:
So the CTFE interpreter doesn't like something to do with your 
chain of ranges. This is not totally unexpected, as the CTFE 
engine has lots of quirks that make it sometimes puke on valid 
CTFE-able code.


:(

At this time, I'd recommend doing your task at runtime anyway. 
Hopefully I have shed some more light on how things are working 
here.


-Steve


Hah yeah, I'll have to switch to runtime for quite a few of the 
tasks. But yes you've explained everything! thanks a lot for 
taking the time :) I guess I'll report the issue with enumerate 
since maybe it's something that should be fixed eventually.


Variable cannot be read at compile time.

2017-12-07 Thread aliak via Digitalmars-d-learn
Hi, I'm having a bit a trouble doing some compile time parsing. 
This works:


immutable str = "he-.llo-the.re";
immutable separators = "-.";
enum a = str.splitter(separators).array;

But this does not:

enum b = str.splitter!(a => separators.canFind(a)).array;

The error is: cannot deduce function from argument types !((a) => 
separators.canFind(a))(immutable(string))


And this does:

enum c = str.splitter!(a => a == a).array;

And this does not:

enum d = str.splitter!(a => a == separators).array;

What am I missing?

Thanks!




cannot deduce template lambda from argument

2017-12-05 Thread aliak via Digitalmars-d-learn

Hi,

Having a little trouble understanding lambda type deduction. I 
have this lambda:


immutable lambda(T) = (T n) => n * n;

and if I call it with an explicit type it works else it errors 
with: lambda cannot deduce function from argument types !()(int)


auto x = lambda!int(2); // ok
auto x = lambda(2); // errors

But if it's a normal template function then calling it without 
explicit type is ok.


Thanks for any help!



Re: cannot deduce template lambda from argument

2017-12-06 Thread aliak via Digitalmars-d-learn

On Wednesday, 6 December 2017 at 08:10:26 UTC, Biotronic wrote:

On Tuesday, 5 December 2017 at 23:01:43 UTC, aliak wrote:

immutable lambda(T) = (T n) => n * n;


Generally, you'd want to write

alias lambda = n => n * n;

instead. That said, I don't see any reason why your syntax 
shouldn't work, and would argue it's a bug. Please file it in 
Bugzilla.


--
  Biotronic


Ok thanks! Done: https://issues.dlang.org/show_bug.cgi?id=18037

Btw, in the case of your suggested approach, what if I want to 
constrain the parameter type?


Re: cannot deduce template lambda from argument

2017-12-06 Thread aliak via Digitalmars-d-learn
On Wednesday, 6 December 2017 at 11:02:01 UTC, Jonathan M Davis 
wrote:
If you only want one type, then given n that type; I'm pretty 
sure that it would be


alias lambda = (int n) => n * n;

if you wanted an int. But if you want to do anything more 
complicated with it, it would make more sense to just turn it 
into a proper function template.


- Jonathan M Davis


Roight, I was more thinking along the lines of a little more 
complicated I guess :)


i.e.:

template lambda(T)
if (isIntegral!T)
{
alias lambda = (T n) => n * n;
}

But you're right, if it gets more complicated a proper function 
is probably better. Plus I just tried and it seems like you can't 
really constrain a variable template anyway. Unless there's some 
magic syntax I've overlooked in the docs.


Thanks!

Thanks!


Re: UFCS syntax I never saw before.

2018-05-22 Thread aliak via Digitalmars-d-learn
On Monday, 21 May 2018 at 14:19:35 UTC, Steven Schveighoffer 
wrote:

On 5/21/18 8:15 AM, SrMordred wrote:

Right, so this should´n be working I think.


struct SomeStruct
{
    void foo(int);
}

SomeStruct s;
s.foo = 10;


I thought that only with @property this will work.



That was the plan, but it got derailed.

Whoever wrote that original line of code, they need a stern 
talking-to.


-Steve


While wearing the naughty pointy hat and sitting in a corner :p


Re: UFCS syntax I never saw before.

2018-05-22 Thread aliak via Digitalmars-d-learn

On Monday, 21 May 2018 at 18:53:19 UTC, Jonathan M Davis wrote:


writeln = "foo";

is legal, and it's dumb, but it hasn't mattered much in 
practice. So, causing a bunch of code breakage in order to 
disallow it is unlikely to go over well. It would also then 
make getters and setters inconsistent in that setters would 
require @property and getters wouldn't. How much that matters 
is debatable, but it does make such a change less palatable.


[...]



Can't assignment to a function be fixed though? Are there any 
cases where fixing that will cause problems for @property free 
functions because they all must take more that one parameter i 
assume.


It's quite a big wart so we don't have to fix all of @property at 
least, but that should be fixed if fixing it does not crap on 
UFCS and @property free functions.




Re: UFCS syntax I never saw before.

2018-05-24 Thread aliak via Digitalmars-d-learn
On Tuesday, 22 May 2018 at 13:59:16 UTC, Steven Schveighoffer 
wrote:
The derailed plan was to leave alone the ability to call no-arg 
functions without parentheses, but to REQUIRE @property to call 
an argument-taking function with the assignment style.


See the DIP here: https://wiki.dlang.org/DIP23

Written by Walter and Andrei. I can't remember why it didn't 
happen.


-Steve


Aha. Thanks for the link!

It feels like the only difference between a no-arg function that 
is @property and one that is not is that the former could be 
invoked with optional parentheses and the latter should be 
illegal with parentheses.


Whereas an argument taking function marked as @property should 
probably allow read or write operations depending on whether or 
not it's invoked with an implicit first argument or not:


@property int f(int) { ... }
1.f; // read op
f = 1; // write op

And to make parentheses illegal as well of course.




Re: Assigning a method name to a variable and then calling it with an object

2018-05-24 Thread aliak via Digitalmars-d-learn

On Thursday, 24 May 2018 at 23:08:29 UTC, Basile B. wrote:

On Thursday, 24 May 2018 at 23:03:21 UTC, aliak wrote:

Hi,

I was essentially trying to do this:

struct S {
  void f() {}
}

auto f = S.f; // f becomes void function(S) ??
S s;
f(s);

Is something like that possible?

Cheers,
- Ali


Sure:

```
import std.stdio;

void main(string[] args)
{

struct S {
  void f() {"yeah possible".writeln;}
}

void delegate() f;
f.funcptr = 
S s;
f.ptr = 
s.f();
}
```

It's just that you have to learn the ABI of D delegates.
There are two members: .funcptr (function) and .ptr (context, 
i.e the "this").


ahh, gracias!





Re: UFCS syntax I never saw before.

2018-05-24 Thread aliak via Digitalmars-d-learn

On Tuesday, 22 May 2018 at 14:33:20 UTC, Jonathan M Davis wrote:
A free function with a single argument works just fine as a 
setter property. e.g. you could do something like


void env(Tuple!(string, string)[] str)
{
// set environment variables
}

env = [tuple("foo", "bar")];

is perfectly legal. I question that there are many cases where 
such a function would be considered good design, but basically 
any case where it would make sense to have a function act like 
a global variable is currently allowed but would be disallowed 
if you couldn't have a setter property with only one argument.


- Jonathan M Davis


That can be attributed with @property if the developer intends 
for it to be used in that way, else should be illegal.





Re: UFCS syntax I never saw before.

2018-05-24 Thread aliak via Digitalmars-d-learn

On Thursday, 24 May 2018 at 22:03:38 UTC, aliak wrote:
It feels like the only difference between a no-arg function 
that is @property and one that is not is that the former could 
be invoked with optional parentheses and the latter should be 
illegal with parentheses.


Edit: err... other way around!





Assigning a method name to a variable and then calling it with an object

2018-05-24 Thread aliak via Digitalmars-d-learn

Hi,

I was essentially trying to do this:

struct S {
  void f() {}
}

auto f = S.f; // f becomes void function(S) ??
S s;
f(s);

Is something like that possible?

Cheers,
- Ali


Re: UCFS does not work for nested functions?

2018-06-18 Thread aliak via Digitalmars-d-learn
On Monday, 18 June 2018 at 17:58:11 UTC, Steven Schveighoffer 
wrote:
What then can happen is that your local calls can get hijacked 
from outside the module, if someone happens to define something 
later that you happened to import. D tries to avoid such 
possibilities.


There's not much precedent for local symbols being overridden 
by module-level symbols.


-Steve


I thought that happens already with non-nested functions:

module a;

struct A {
  void f(); // assume it's added later
}

module b;
import a;

void f(A) { }
void g() {
  auto x = A();
  a.f(); // this would be calling local f until someone added A.f
}

Or I misunderstood what you said?

Cheers,
- Ali

PS: This is something I've worried about before actually [1] when 
I was more of a noob than now, but I've come to accept I guess :) 
... though I could still be misunderstanding things of course :/


https://forum.dlang.org/post/crcbaautgmrglhzvx...@forum.dlang.org



Re: UCFS does not work for nested functions?

2018-06-18 Thread aliak via Digitalmars-d-learn
On Monday, 18 June 2018 at 14:19:30 UTC, Steven Schveighoffer 
wrote:

On 6/18/18 7:16 AM, Bastiaan Veelo wrote:

On Sunday, 18 May 2014 at 08:15:08 UTC, Steffen Wenz wrote:

Hi,

Just noticed that using UFCS does not work for nested 
functions, and was wondering whether that's intended, and 
what the rationale behind it is:


I just had the same question.

I can imagine that the context pointer of nested functions 
complicates things, but making `bar` `static` does not help. 
Has anything changed in recent years regarding the difficulty 
of implementing UFCS for nested functions? Would it be easier 
to only support static nested functions?


```
void main() {
     static void bar(int x) {}

     int x;
     x.bar(); // Error: no property 'bar' for type 'int'
}
```


It's never been supported, and likely will not be. I think the 
idea is that you can override expected behavior inside by 
accidentally defining some function locally with the same name.


-Steve


Wondering how this is different than with non-nested functions? 
If a global function has the same name as a member function then 
the member function takes precedence. So wouldn't the same thing 
just apply here if it were supported?


Cheers,
- Ali


Re: scope(success) lowered to try-catch ?

2018-06-18 Thread aliak via Digitalmars-d-learn
On Monday, 18 June 2018 at 12:48:46 UTC, Steven Schveighoffer 
wrote:

On 6/17/18 11:58 PM, Neia Neutuladh wrote:

[...]


Yep, it's a good point. But also not the only way to do this. 
If you are returning void, just a goto would work:


[...]


I'm quite a noob when it comes to compiler stuff, and I see how 
this can be optimized when there're no exceptions, but I wonder 
what scope(success) actually means though without exceptions in 
play. It's just scope(exit) then right or?


Cheers,
- Ali



Re: How to list all the manifest constants in a class or struct

2018-06-17 Thread aliak via Digitalmars-d-learn

On Sunday, 17 June 2018 at 02:44:38 UTC, Heromyth wrote:

Here is a struct named S:

struct S
{
enum X = 10;
enum Y
{
  i = 10
}
enum Z = "str";
struct S {}
class C {}

static int sx = 0;
__gshared int gx = 0;

shared void g();
}

I want list all then the manifest constants in it.

I searched the std.traits and this forums, but get nothing.
Maybe, my real question is how to get the storage class for a 
member in a class or struct.


Thanks.


I think this bolts.isManifestAssignable [1] will get you 
partially there. The place where it'll fail though is a static 
immutable (since they are assignable to manifest constants) but 
you can filter those by seeing if you can take the address, 
something like:


foreach (m; __traits(allMembers, T)) {
  if (isManifestAssignable!(T, m) && !is(typeof(mixin(""~m))) {
// it's a manifest constant ... (?)
  }
}

There of course might be edge cases I can't think of/don't know 
about though.


Cheers,
- Ali

http://bolts.dpldocs.info/bolts.traits.isManifestAssignable.html




Re: WTF! new in class is static?!?!

2018-06-07 Thread aliak via Digitalmars-d-learn

On Thursday, 7 June 2018 at 21:32:54 UTC, Jonathan M Davis wrote:


struct S
{
int* ptr = new int(42);
}



Is that supposed to compile? -> https://run.dlang.io/is/SjUEOu

Error: cannot use non-constant CTFE pointer in an initializer 
&[42][0]


Re: overload .

2018-06-25 Thread aliak via Digitalmars-d-learn

On Monday, 25 June 2018 at 13:37:01 UTC, Mr.Bingo wrote:


One can overload assignment and dispatch so that something like

A.x = ... is valid when x is not a typical member but gets 
resolved by the above functions.


Therefore, I can create a member for assignment. How can I 
create a member for getting the value?


A.x = 3; // Seems to get translated in to A.opDispatch!("x")(3)

works but

foo(A.x); // fails and the compiler says x does not exist


I need something consistent with opDot. I am trying to create 
"virtual"(not as in function) fields and I can only get 
assignment but not accessor.


A.x is translated in to A.opDispatch!"x" with no args. So I guess 
you can overload or you can static if on a template parameter 
sequence:


import std.stdio;
struct S {
auto opDispatch(string name, Args...)(Args args) {
static if (!Args.length) {
return 3;
} else {
// set something
}
}
}
void main()
{
S s;
s.x = 3;
writeln(s.x);
}

Cheers,
- Ali


Re: anyway to pass the context of an inner type to a template so it can be constructed?

2018-06-27 Thread aliak via Digitalmars-d-learn

On Wednesday, 27 June 2018 at 14:01:03 UTC, Alex wrote:

On Wednesday, 27 June 2018 at 12:02:10 UTC, aliak wrote:

===
The use case is for a non-nullable type, where I want to 
guarantee that the value inside will never be null. I can't do 
it for inner classes though. And I can't allow the user to do 
something like:


void main() {
class C {}
auto s = construct(new C);
}

Because I can't guarantee that's not null.


Cheers,
- Ali


Is there any reason, why you don't want to use a struct? An 
instance of such is never null, still having access to its 
context, if it is a function.


Sorry, by non-nullable I meant not null. It's that construct 
produces a wrapper type that has an internal value that I want to 
guarantee is not null. So whether T is a struct or class is 
dependent on the user of construct.


- Ali


Re: anyway to pass the context of an inner type to a template so it can be constructed?

2018-06-27 Thread aliak via Digitalmars-d-learn

On Wednesday, 27 June 2018 at 19:28:37 UTC, Timoses wrote:

Can't seem to avoid using mixin in main..


hehe yeah I see, didn't think of trying mixins, worth a shot! It 
seems like you had fun at least ;)





Re: overload .

2018-06-25 Thread aliak via Digitalmars-d-learn

On Monday, 25 June 2018 at 15:39:09 UTC, Mr.Bingo wrote:

On Monday, 25 June 2018 at 13:58:54 UTC, aliak wrote:
A.x is translated in to A.opDispatch!"x" with no args. So I 
guess you can overload or you can static if on a template 
parameter sequence:


import std.stdio;
struct S {
auto opDispatch(string name, Args...)(Args args) {
static if (!Args.length) {
return 3;
} else {
// set something
}
}
}
void main()
{
S s;
s.x = 3;
writeln(s.x);
}

Cheers,
- Ali


Ok, for some reason using two different templated failed but 
combining them in to one passes:


auto opDispatch(string name, T)(T a)
auto opDispatch(string name)()

Maybe it is a bug in the compiler that it only checks one 
opDispatch?


Two opDispatchs as in:

import std.stdio: writeln;
struct S {
void opDispatch(string name, T)(T t) {
writeln(t);
}

auto opDispatch(string name)() {
writeln("ret");
return 4;
}
}

void main() {
S s;
s.x;
s.x = 4;
}

??

The above seems to work fine. Or maybe you meant something else?



Re: template sequence parameters treats member functions differently?

2018-06-25 Thread aliak via Digitalmars-d-learn
On Monday, 25 June 2018 at 15:06:42 UTC, Steven Schveighoffer 
wrote:

On 6/24/18 5:19 PM, aliak wrote:

[...]


No, because the alias is an alias to the function, not the 
delegate.


The act of taking the address creates the delegate, where the 
delegate's ptr is the context pointer (i.e. s), and the funcptr 
is the function that accepts the pointer (i.e. S.f).


When you pass in s.f to an alias, you are actually passing in 
S.f. It's the fact that you are looking in the *namespace* of s 
when you do the alias. The  is special for the compiler, 
and can't be deferred to later.


Ahh, I see. Ah well. So not really much i can do here with this 
then I guess. Thanks for explaining though!




BUT, I'm thinking this may be fixable, as it's inconsistent 
with inner functions:


auto foo(alias x)() { return x(); }

struct S
{
   int bar() { return 42; }

   // int baz() { return foo!bar; } // nope
}

void main()
{
   S s;

   int bar() { return 42; }

   assert(foo!bar() == 42); // ok
   // assert(foo!(s.bar) == 42); // nope

   int baz() { return s.bar; }
   assert(foo!baz() == 42); // ok!
}

I don't see any reason why the alias is to the function and not 
the contexted function. I don't see how it's any different from 
the ones which use inner functions.


-Steve


I can only agree - me no see either. And having no clue as to how 
the compiler is implemented, I cannot even conjecture :)




Re: template sequence parameters treats member functions differently?

2018-06-25 Thread aliak via Digitalmars-d-learn
On Monday, 25 June 2018 at 18:59:37 UTC, Steven Schveighoffer 
wrote:

On 6/25/18 2:51 PM, aliak wrote:
On Monday, 25 June 2018 at 15:06:42 UTC, Steven Schveighoffer 
wrote:


I don't see any reason why the alias is to the function and 
not the contexted function. I don't see how it's any 
different from the ones which use inner functions.


I can only agree - me no see either. And having no clue as to 
how the compiler is implemented, I cannot even conjecture :)




Well, it's worth an enhancement request in any case.

-Steve


doneo: https://issues.dlang.org/show_bug.cgi?id=19026


template sequence parameters treats member functions differently?

2018-06-24 Thread aliak via Digitalmars-d-learn
Hi, I'm having some issues with template sequence parameters, it 
seems they are not typed as delegates inside a template, but are 
outside. I.e.


template T(V...) {
alias T = typeof([0]);
}

struct S { void f() {} }
S s;

pragma(msg, T!(s.f)); // void function()
pragma(msg, typeof()); // void delegate()

How come the output is different? Is it supposed to be the same?

What I'm trying to do is write a template that can give me a 
tuple of types for all values of the sequence passed in, so that 
I can index in to the type tuple. Seems to work well except for 
this member function part, working source here:


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

Specifically the commented out line is what I would like to be 
able to get working if possible.


Thanks for any help,
- Ali





Re: Wrapping a forward range in another forward range

2018-06-24 Thread aliak via Digitalmars-d-learn

On Sunday, 24 June 2018 at 20:33:32 UTC, Rudy Raab wrote:
So I have an XLSX (MS Excel 2007+ file format) library that I 
wrote  (https://github.com/TransientResponse/dlang-xlsx) that I 
recently converted from std.xml to dxml. That went well and it 
still works (much faster too).


[...]


I think it's the isSomeChar!(ElementType!R), not the 
isRandomAccessRange (because string isSomeString and !isSomeChar)?


Cheers,
- Ali



anyway to pass the context of an inner type to a template so it can be constructed?

2018-06-27 Thread aliak via Digitalmars-d-learn

This currently fails unless you mark the class as static:

auto construct(T)() {
return new T;
}
void main() {
class C {}
auto s = construct!C;
}

So wondering if there's anything that can be done to get the 
above working?



Or if there isn't then how could the compiler be enhanced to 
allow for something like this if possible?


===
The use case is for a non-nullable type, where I want to 
guarantee that the value inside will never be null. I can't do it 
for inner classes though. And I can't allow the user to do 
something like:


void main() {
class C {}
auto s = construct(new C);
}

Because I can't guarantee that's not null.


Cheers,
- Ali


what's the correct way to handle unicode? - trying to print out graphemes here.

2018-07-03 Thread aliak via Digitalmars-d-learn
Hi, trying to figure out how to loop through a string of 
characters and then spit them back out.


Eg:

foreach (c; "‍‍‍️‍") {
  writeln(c);
}

So basically the above just doesn't work. Prints gibberish.

So I figured, std.uni.byGrapheme would help, since that's what 
they are, but I can't get it to print them back out? Is there a 
way?


foreach (c; "‍‍‍️‍".byGrapheme) {
  writeln(c.);
}

And then if I type the loop variable as dchar,  then it seems  
that the family empji is printed out as 4 faces - so the code 
points I guess - and the rainbow flag is other stuff (also its 
code points I assume)


Is there a type that I can use to store graphemes and then output 
them as a grapheme as well? Or do I have to use like lib ICU 
maybe or something similar?


Cheers,
- Ali


Re: what's the correct way to handle unicode? - trying to print out graphemes here.

2018-07-03 Thread aliak via Digitalmars-d-learn

On Tuesday, 3 July 2018 at 13:32:52 UTC, aliak wrote:
Hi, trying to figure out how to loop through a string of 
characters and then spit them back out.


Eg:

foreach (c; "‍‍‍️‍") {
  writeln(c);
}

So basically the above just doesn't work. Prints gibberish.

So I figured, std.uni.byGrapheme would help, since that's what 
they are, but I can't get it to print them back out? Is there a 
way?


foreach (c; "‍‍‍️‍".byGrapheme) {
  writeln(c.);
}

And then if I type the loop variable as dchar,  then it seems  
that the family empji is printed out as 4 faces - so the code 
points I guess - and the rainbow flag is other stuff (also its 
code points I assume)


Is there a type that I can use to store graphemes and then 
output them as a grapheme as well? Or do I have to use like lib 
ICU maybe or something similar?


Cheers,
- Ali


Hehe I guess the forum really is using D :p

The two graphemes I'm talking about (which seem to not be 
rendered correctly above) are:


family emoji: https://emojipedia.org/family-woman-woman-boy-boy/
rainbow flag: https://emojipedia.org/rainbow-flag/



Re: How do you safely deal with range.front?

2017-12-30 Thread aliak via Digitalmars-d-learn

On Friday, 29 December 2017 at 20:47:44 UTC, Dukc wrote:

On Friday, 29 December 2017 at 19:38:44 UTC, aliak wrote:
So when I'm dealing with ranges, there're a number of times 
where I get the front of the returned result of a set of 
operations, but of course there is no front so you get an 
runtime access error.


This could be what you want:

auto makeInfinite(Range)(Range ofThis)
{   import std.range;
return ofThis.chain(typeof(ofThis.front).init.repeat);
}

void main()
{   import std.stdio, std.range;
auto testArray = [2, 3, 4].makeInfinite;
foreach(e; testArray.take(5)) e.writeln;
readln(); //stops the console from closing immediately;
}

/+
2
3
4
0
0
+/


Hmm, interesting. Not sure that's what I'm looking for but I like 
it anyway :)


I'm more looking to deal with situations like this:

Instead of this:
  auto result = range.op!f;
  if (!result.empty) {
result.front.method();
  }

This:
  range.op!f.ifFront.method();


In the above scenario I only want method to be called if the 
pipeline resulted in any element left in the range.


On the other hand, I really do not recommend using ranges that 
way as a default. Most often you do not want to call front() or 
popFront() of an empty range in the first place. So if you end 
up doing so accidently, you want to know it. If it just 
returned some default value chances would be you never notice 
you have a bug. That's why front() in debug mode is usually 
programmed to termitate the program when it's called 
incorrectly.


True you don't want to call front on empty, but sometimes I only 
care to call a method on front if it's there. Where the situation 
necessitates the existence of front, and not having a front is 
indeed a bug, then you want the program to terminate, yes. But 
not otherwise.





Re: How do you safely deal with range.front?

2017-12-30 Thread aliak via Digitalmars-d-learn

On Friday, 29 December 2017 at 20:11:03 UTC, Seb wrote:

On Friday, 29 December 2017 at 19:38:44 UTC, aliak wrote:

Hi,

So when I'm dealing with ranges, there're a number of times 
where I get the front of the returned result of a set of 
operations, but of course there is no front so you get an 
runtime access error.


[...]


Do you know about the proposed `orElse`?

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


Oh cool. No I did not. Seems like a nice approach. It would incur 
the creation of a new object when one doesn't exist, which I 
guess would be fine for many situations, and would work for this 
as well probably, but it'd be nice to avoid it as well in some 
situations.


Just going thought std a bit now and I found this: 
https://dlang.org/library/std/typecons/black_hole.html


That would be pretty cool to have 
range.op!f.blackHoleFront.call() - though blackHoleFront sounds 
horrible :p


Re: How do you safely deal with range.front?

2017-12-30 Thread aliak via Digitalmars-d-learn
On Friday, 29 December 2017 at 20:33:22 UTC, Jonathan M Davis 
wrote:
Well, I don't know what you're really doing in code here, but 
in general, you'd write your code in a way that it checks empty 
and simply doesn't try to do anything with front if the range 
is empty.


Yes, ideally, if programmers were perfect, this would work. The 
same applies to always checking null before dereferencing a 
pointer. You can of course try and make sure you always do check 
first. Or you can provide a safe way to do it in cases where you 
only want to dereference a pointer if the pointer is not null. 
Granted in some situations you want to crash as well because it 
would indeed be a bug if a pointer was null (or a range was 
empty).


Btw, it seems that phobos, or at lest some of it, has an 
assert(!empty, "Attempting to fetch the front of an empty 
filter."). I guess probably it's not everywhere so hence the 
weird behavior you say happens sometimes :(  ... ah well.


You could wrap the range in a range that specifically returns 
some default element when the wrapped range is empty, meaning 
that the range would then be infinite.


You could just use a wrapper function to call front and have it 
return a Nullable or a default value if the range is empty, but 
that wouldn't work when passing the range to other functions.


You could also do something like an infinite range that simply 
returns the same value forever no matter how often front gets 
popped, and then you could use chain to combine your range and 
that range into a single range that would iterate through your 
range and then give the same element forever.


Regardless, you'll have to be careful of any solution that 
involves creating an infinite range, since while some 
algorithms will be fine with it, others will either not compile 
or result in an infinite loop (e.g. don't use foreach on it).




True, having to deal with infinite ranges will add to number of 
cases I'd have to worry about. Would prefer not to of course.


I'm going to explore the Nullable approach you mentioned a bit me 
thinks !


Also, I found this now: 
https://forum.dlang.org/post/fshlmahxfaeqtwjbj...@forum.dlang.org 
. Seems to be what I'm looking for!


Regardless, if you want to return an element when there isn't 
one, you're going to have to come up with a value for that. 
It's not something that's really going to work well generically.


The generic constructs would occur ideally before accessing 
front. If not then yes, you're correct. Passing a "safeFront", or 
any other non-range value further down the pipeline would need a 
an undo function the other end of the pipeline.








Re: How do you safely deal with range.front?

2017-12-31 Thread aliak via Digitalmars-d-learn

On Sunday, 31 December 2017 at 01:03:17 UTC, Tony wrote:
For me, front() should throw a pre-defined exception when 
called on an empty range in order to eliminate undefined 
behavior. It does take some time to make a check, but D does 
array bounds checking by default. Ideally the front() check 
could be turned off somehow ("-boundschecks=off") by the user 
for those who want maximum speed, but I guess there is no way 
to do that when using pre-compiled functions in a library.


That sounds like a good idea. Wouldn't the same apply to array 
bounds checking for precompiled functions though?


Also, is going out of array bounds well defined behavior in D 
even with boundscheck off? And any links to docs on UB in D?


Re: Converting array in to aliased tuple type.

2017-12-25 Thread aliak via Digitalmars-d-learn

On Monday, 25 December 2017 at 14:08:08 UTC, Mengu wrote:


since Point is a Tuple and does not have a constructor that 
takes a list of integers (int[]), you should have a helper 
function.


Aukay :(

I was kind of hoping for some magical D variadic alias template 
on Tuple or something that will just deconstruct the arguments in 
to tuple components.





Re: Does to!(string)(char[]) do any memory allocation on conversion?

2017-12-25 Thread aliak via Digitalmars-d-learn

On Monday, 25 December 2017 at 14:12:32 UTC, Marc wrote:
Does to!(string)(char[]) do any memory allocation on conversion 
or is this similar to a cast or what else?


As said it calls idup, which calls _trustedDup which seems to 
call _dup which does memory allocation -> 
https://github.com/dlang/druntime/blob/v2.077.1/src/object.d#L3863


I think you can use assumeUnique to avoid allocs though. See code 
gen here:


https://godbolt.org/g/44pLpL



How do you safely deal with range.front?

2017-12-29 Thread aliak via Digitalmars-d-learn

Hi,

So when I'm dealing with ranges, there're a number of times where 
I get the front of the returned result of a set of operations, 
but of course there is no front so you get an runtime access 
error.


In some other languages the concept of "front" or "first" returns 
a safe referece, or optional value that calling methods on will 
not crash the program.


I'm thinking of maybe making something like

safeFront(R)(R r) {
  return r.empty ? SafeRef!(ElementType!R) : SafeRef(r.front);
}

Where SafeRef, I think, can provide an overload for opDispatch 
and just forward the calls to the stored reference of r.front. If 
the stored reference is null then it can return a SafeRef to the 
return value of whatever was being dispatched to.


Is there another way to go about this? Maybe through naturally 
using r.front instead of making a r.safeFront alternative?


Cheers


static if and early exit from function doesn't seem to work?

2017-12-31 Thread aliak via Digitalmars-d-learn
Alo! I'm making a recursive concat function that is similar to 
chain. The following code works:


import std.range: isInputRange;

auto concat(R, V...)(R range, V values) if (isInputRange!R) {
import std.range: chain, ElementType;
static if (V.length) {
static if (isInputRange!(V[0])) {
return range.chain(values[0]).concat(values[1..$]);
} else static if (is(V[0] == ElementType!R)) {
return range.chain([values[0]]).concat(values[1..$]);
} // add an else assert here.
} else {
return range;
}
}

But the following does not:

auto concat(R, V...)(R range, V values) if (isInputRange!R) {
import std.range: chain, ElementType;
static if (!V.length) {
return range;
}
static if (isInputRange!(V[0])) {
return range.chain(values[0]).concat(values[1..$]);
}
static if (is(V[0] == ElementType!R)) {
return range.chain([values[0]]).concat(values[1..$]);
}
}

You get a:

Error: tuple index 0 exceeds 0
Error: template instance range.concat.concat!(Result) error 
instantiating


So it seems it tries to compile the statements below the check on 
V.length even though it's guaranteed to be true and there's a 
return statement inside the if.


Is it a current limitation of static if? or a bug? or is 
something like this just not possible because of something I'm 
not seeing?


Cheers



Converting array in to aliased tuple type.

2017-12-25 Thread aliak via Digitalmars-d-learn
Hi, been looking for a way to convert an array to a tuple, but 
can't seem to find one. Is there one?


Looking for something like:

alias Point = Tuple!(int, "x", int, "y");
enum data = "1,2:8,9";
auto points = data
  .split(':')
  .map!(a => a
.split(',')
.map!(to!int)
  )
  .map!Point; // <-- this works if you do `.map!(a => Point(a[0], 
a[1]));` instead


Cheers!



Re: Define enum value at compile time via compiler argument?

2017-12-25 Thread aliak via Digitalmars-d-learn

On Monday, 25 December 2017 at 16:38:32 UTC, Thomas Mader wrote:

On Monday, 25 December 2017 at 16:22:11 UTC, Mengu wrote:

is it a relative path? if so:

pragma(msg, 
__FILE_FULL_PATH__.split("/")[0..$-1].join("/"));



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


Nice idea but it is an absolute path. :-/


Can you use the -J compiler flag to define a string import file?
Then you can:
string data = import("file.txt");




Re: __traits(isSame, TemplateOf ...) errors and some Idiomatic D questions

2018-01-08 Thread aliak via Digitalmars-d-learn

On Monday, 8 January 2018 at 23:03:46 UTC, H. S. Teoh wrote:
On Mon, Jan 08, 2018 at 10:59:44PM +, aliak via 
Digitalmars-d-learn wrote: [...]
onlineapp.d(61): Error: template std.traits.TemplateOf does 
not match any template declaration. And I use it like this:


enum r1Sorted = __traits(isSame, TemplateOf!(R1), SortedRange);


This seems unnecessarily complicated.  What about this instead?

enum r1Sorted = is(R1 : SortedRange!T, T...);

Basically, what that is-expression means is: "Is R1 a template 
of the form `SortedRange!T` where T is some list of template 
arguments".


Generally, using __traits directly is usually not recommended 
unless there's no other way to achieve what you want.



T


Wow nice! Super nice :D Thanks! And ah I see, I suppose the 
double underscore kinda hints at that as well?


Re: __traits(isSame, TemplateOf ...) errors and some Idiomatic D questions

2018-01-08 Thread aliak via Digitalmars-d-learn

On Monday, 8 January 2018 at 23:22:04 UTC, Seb wrote:

On Monday, 8 January 2018 at 23:14:32 UTC, Seb wrote:
Your problem is that `TemplateOf!(int[])` isn't defined. It 
should probably be changed to return `void`.


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


Damn that's some fast turnaround! And thanks for the explanation 
as well :)


Cheers


__traits(isSame, TemplateOf ...) errors and some Idiomatic D questions

2018-01-08 Thread aliak via Digitalmars-d-learn
Hi, trying to write some idiomatic generic D code and I'm a bit 
stuck with using the TemplateOf to check if a range is a 
SortedRange or not. A bit about the code, I'm basically rewriting 
https://dlang.org/library/std/algorithm/setops/set_difference.html but I want to do different things based on if the passed in ranges are sorted or not.


The error I'm getting is this:

onlineapp.d(61): Error: template std.traits.TemplateOf does not 
match any template declaration. And I use it like this:


enum r1Sorted = __traits(isSame, TemplateOf!(R1), SortedRange);

That's happening on line 61 and the weird thing is that I'm using 
TemplateOf exactly (i think) the same way on lines 28 and 29 and 
those do not error.


The code is here: https://run.dlang.io/is/9fowuP

If I substitute the isSame trait with compiles, then it works:

enum r1Sorted = __traits(compiles, TemplateOf!(R1), SortedRange);
pragma(msg, r1Sorted); // prints true

Any help would be appreciated! And on a side note, if anyone can 
point out any things I'm doing wrong when it comes to using D 
optimally/properly then please do.


Cheers! And thanks for any help!

PS:

1) Is there a better way to check if a predicate is unary or 
binary?
2) Is there an idiomatic way to check if a range is sortable or 
is it just "is(typeof(sort(range)))" basically it?





Rewriting a c++ template to D (replacing iterator with ranges "properly")

2018-01-26 Thread aliak via Digitalmars-d-learn
It basically steps through in a stride and sets the checkpoints 
to false.


C++:
template 
void mark(It begin, It end, N step) {
  assert(begin != end)
  *begin = false;
  while (end - begin > step) {
begin = begin + step;
*begin = false;
  }
}

For D this is what I figured would be the way?

void mark(R, N)(auto ref R range, N step)
if (
  /* 1 */ isIntegral!N
  /* 2 */ && isRandomAccessRange!R
  /* 3 */ && is(ElementType!R == bool)
  /* 4 */ && hasAssignableElements!R
) {
  range.front = false;
  while (!range.empty) {
range.popFrontN(N);
range.front = false;
  }
}

I have a more specific question too:

1) I've seen some phobos code checking for assignability like 
this:


  is(typeof(range.front = false))

... is that an advantage of that over hasAssignableElements? Or 
is that just basically combining constraints 3 and 4 which I have 
above?


2) Say I wanted to restrict to only lvalue ranges passed in as 
inputs. Does that mean I use hasLvalueElements as a constraint or 
is remove the "auto" and just have a ref parameter sufficient?


Cheers


Re: Rewriting a c++ template to D (replacing iterator with ranges "properly")

2018-01-26 Thread aliak via Digitalmars-d-learn

On Friday, 26 January 2018 at 14:16:04 UTC, aliak wrote:

  range.front = false;
  while (!range.empty) {
range.popFrontN(N);
range.front = false;
  }
}


Oops, this should be:

while (!range.empty) {
  range.front = false;
  range.popFrontN(N);
}



Re: getting member functions of a struct and Error: identifier expected following ., not this

2018-01-24 Thread aliak via Digitalmars-d-learn

On Wednesday, 24 January 2018 at 07:55:01 UTC, thedeemon wrote:

On Tuesday, 23 January 2018 at 00:00:38 UTC, aliak wrote:

[...]


The struct defined inside a scope can mention variables defined 
in that scope (e.g. use them in its methods), so it needs a 
pointer to the place where those closed variables live. That's 
the main difference between such struct and a static one that 
cannot use those scope vars. I guess you're seeing that pointer 
as additional member.



As for static foreach, when you write a simple foreach over 
some compile-time tuple (like in this case), it's unrolled at 
compile time similarly to "static foreach", the main difference 
is whether it creates a sub-scope for the loop body or not. 
"foreach" creates one, "static foreach" doesn't.


Ah makes sense. Thanks!


Re: Voldemort type for mixin template.

2018-01-11 Thread aliak via Digitalmars-d-learn

On Thursday, 11 January 2018 at 08:56:11 UTC, ChangLong wrote:
When I try add some sub type for struct with mixin template, 
seems there is no way to hidden the private type.


Is there a way to hidden type from mix template like Voldemort 
type ?


fake code:

mix template TypeX () {
alias This = typeof(this);

static struct Unique {
   This* _ptr ;
}
static struct Helper {
  private Unique data;
 }
 alias TypeX = {
 alias PublicName = Helper ;
 }
}

struct Node {
mixin TypeX!();
PublicName helper;
}


Hi, can you explain a bit more? The question is not entirely 
clear to me. Can you mixin a struct of type PublicName and just 
hide everything in there?


mixin template TypeX() {
struct PublicName {
private alias This = typeof(this);
private struct Unique {
This* _ptr;
}
private Unique _data;
alias _data this;
}
}

void main(string[] args) {
mixin TypeX;
PublicName helper;
helper._ptr.writeln;
}

Cheers



Can you introspect predicate arity and if it's an equality predicate?

2018-01-11 Thread aliak via Digitalmars-d-learn

Hi, so basically is there a way to:

void func(alias pred = null, Range)(Range range) {
  // 1) check if pred(ElementType!Range.init, 
ElementType!Range.init) is equality

  // 2) check if isUnary!pred
  // 3) check if isBinary!pred
}

I think maybe the isUnary or isBinary may not work unless it 
takes an extra parameter that gives it some context, i.e. 
isBinary!(pred, T, U) where T and U are the parameter types.


Currently I have this for an isUnary

template isUnary(alias pred) {
static if (is(typeof(pred) : string))
{
enum isUnary = is(typeof(unaryFun!pred(0)));
}
else static if (is(Parameters!pred F) && F.length == 1)
{
enum isUnary = true;
}
else
{
enum isUnary = false;
}
}

But that does not seem to work in this situation:

isUnary!(a => a) // returns false

It won't work if I do isUnary!"a(2)" for e.g, in the case that T 
is callable or isUnary!"a.x" in the case that "a" is a struct 
with a member x ... just to name a couple of cases.


If I give context then all's good:

enum isUnaryOver = is(typeof(unaryFun!pred(T.init))); // works

isEqualityFunction Im not sure how to go about. So open to any 
ideas, or if there're already some traits or something I can use. 
I was thinking I could do:


alias E = // some element type
static if (isBinary!(pred, E) && binaryFun!pred(E.init, E.init) 
== true)

{
  // is equality ... but the for double.init is NaN == NaN ?
  // and probably some other things I'm not thinking about.
}

Advice and/or suggestions?

Cheers

PS: the purpose of the isEqualityFunction is to determine whether 
I should use the predicate for sorting or for just for searching, 
so:


f!"a < b"(range) // range is sorted and then operated on
f!"a == b"(range) // range is not sorted and is operated on by 
leveraging pred


Re: Rewriting a c++ template to D (replacing iterator with ranges "properly")

2018-01-26 Thread aliak via Digitalmars-d-learn

On Friday, 26 January 2018 at 14:35:25 UTC, Meta wrote:

On Friday, 26 January 2018 at 14:16:04 UTC, aliak wrote:
1) I've seen some phobos code checking for assignability like 
this:


  is(typeof(range.front = false))

... is that an advantage of that over hasAssignableElements? 
Or is that just basically combining constraints 3 and 4 which 
I have above?


Where did you see this? That's got to be some very old code; I 
can't think of any instance where you would not want to use 
`hasAssignableElements` instead.


Seems to occur in 
https://github.com/dlang/phobos/blob/v2.078.1/std/algorithm/mutation.d


eg: 
https://github.com/dlang/phobos/blob/v2.078.1/std/algorithm/mutation.d#L555





Re: Rewriting a c++ template to D (replacing iterator with ranges "properly")

2018-01-26 Thread aliak via Digitalmars-d-learn

On Friday, 26 January 2018 at 14:59:09 UTC, Simen Kjærås wrote:
what is N here? You're declaring it to be an int value in the 
template<> definition, and then use it as a type in the 
function definition.


Oops again :) Should've been typename N (where N is some integral 
type).


Not exactly. range.front will assert after the last popFrontN 
(since the range is empty).


Ya, sorry, realized this a bit after I posted.

It's trying to combine 3 and 4 I think, but it fails because 
this is allowed in D:


int a;
a = false;


Ah true, so it's more of a is(ElementType!R : bool) check?



You'll want to pass the range as ref. hasLvalueElements checks 
if the elements have lvalue semantics


Doh, of course. It's in the name even!


import std.range;

struct R {
int[3] elements;
int index;

ref auto front() {
return elements[index];
}

void popFront() {
++index;
}

bool empty() {
return index >= elements.length;
}
}

unittest {
assert(hasLvalueElements!(R));
auto a = R([1,2,3], 0);
auto b = a;
b.front = 4;
assert(a.elements == [1,2,3]);
assert(b.elements == [4,2,3]);
}

As we can see, b is a complete copy of a, and changing b does 
not change a. The exact same behavior would occur if a was 
passed by value to a function.


--
  Simen


Thanks for the input!




Re: questions around mutating range algorithms, const, and return ref

2018-01-30 Thread aliak via Digitalmars-d-learn

On Tuesday, 30 January 2018 at 09:51:18 UTC, Ali Çehreli wrote:

> [...]
is trying to
> [...]

It's the same with C++: A type with a const member cannot have 
a compiler-generated assignment operator.


Ok, that made it obvious :)


'const' as a member function attribute is meaningful: It makes 
the implicit 'this' parameter const. Same as a function 
parameter attribute in that regard.


>>> [...]
I can
>> [...]
as in move
>> [...]
the
>> [...]
point.
> [...]
constructed,
> [...]

I'm not happy that I can answer that question. At least I 
opened a bug about some part of the confusion recently. :)


  https://issues.dlang.org/show_bug.cgi?id=18036

Ali


ah, ok. Gotcha, thanks again, Ali.



questions around mutating range algorithms, const, and return ref

2018-01-28 Thread aliak via Digitalmars-d-learn
Hello, I'm trying to write a function called "pull" that, given 2 
ranges, "pull"s the values from range 2 out of range 1. I'm not 
sure if I'm doing it correctly though, and I have some questions 
so any help is appreciated. This is what I have:


ref pull(R1, R2)(return ref R1 r1, R2 r2) {
import std.algorithm, std.array, std.range;
int numFound = 0;
auto r = r1.save;
ElementType!R1[] unfoundElements;
foreach (e; r) {
if (!r2.canFind(e)) {
unfoundElements ~= e;
} else {
numFound++;
}
}
moveEmplaceAll(unfoundElements, r1);
r1.popBackN(numFound);
return r1;
}

So my questions are:

1) So first of all, is there a function like this in phobos that 
I can use? From what I understand phobos is supposed to be nogc 
so mutating functions like these are usually in place ones?


2) Is there a way to avoid the extra "moveEmplaceAll" call 
towards the end and still get the same results?


3) Is it necessary to always import std.array (or std.range: 
empty, front) when doing work like this with range algorithms? 
(otherwise you get no property save when an array is used as a 
range)


4) is the .save necessary? My (initial) tests seem to show that 
it works without, but from my understanding of what save does, it 
feels like it's necessary.


5) return ref and -dip25 ... is that something that's going to 
become default at some time? Is there a timeline? (also curious 
about dip1000 for that matter).


6) It will not work when I pass in a range that has const 
elements.


ie:

const(int)[] arr = [1, 2, 3, 4, 5];
arr.pull([2, 3]);

This I guess makes sense because moveEmplaceAll depends on 
isInputRange and from my understanding, a const range cannot be 
one (is that correct?). So am I correct in thinking there really 
is no way around this, or is there some move/cast trickery that I 
can use maybe?


Cheers,
- Ali


Re: Lambda returning a lambda?

2018-02-02 Thread aliak via Digitalmars-d-learn

On Friday, 2 February 2018 at 01:31:15 UTC, Seb wrote:

Are you aware of partial?

https://dlang.org/phobos/std_functional.html#partial


Si si :)

And now I'm thinking, practically, that might be enough. So 
thanks for the prod.





Can you constrain a type based on properties of what it is being referenced by?

2018-02-02 Thread aliak via Digitalmars-d-learn

To further explain what I mean:

struct A if (!is(this == immutable) && !is(this == shared))
{
}

shared a = A() // error
auto a = A() // ok
immutable a = A() // error
const a = A() // ok

Fake syntax above of course.

I was thinking about this because I read a few posts about const, 
and approaching it via allowing an object to define a head 
mutable version of itself (see post in general forum by Simon for 
details [1])


And there're few constructs like RefCounted which don't make 
sense with an immutable qualifier.


And then there're situations where a mutable version does not 
make sense (I think this would be a much bigger application), ie: 
handles, resource identifiers, application configuration details, 
etc.


[1] 
https://forum.dlang.org/thread/cpxfgdmklgusodqou...@forum.dlang.org




Re: Can you constrain a type based on properties of what it is being referenced by?

2018-02-02 Thread aliak via Digitalmars-d-learn

On Friday, 2 February 2018 at 14:19:37 UTC, aliak wrote:


...  (see post in general forum by Simon for details [1])


*Simen

Gah! Sorry!


Lambda returning a lambda?

2018-02-01 Thread aliak via Digitalmars-d-learn

Is there a way to do this:

import std.stdio;

void main()
{
alias f = (a) => (b) => a * b;
f(2)(3).writeln;
}

Error now is: Error: template lambda has no type

Cheers


Re: Rewriting a c++ template to D (replacing iterator with ranges "properly")

2018-01-27 Thread aliak via Digitalmars-d-learn

On Friday, 26 January 2018 at 23:15:41 UTC, Simen Kjærås wrote:


The function is called fill, and assigns a value to every 
element in the range. If a[0] = false compiles, we also want 
a.fill(false) to compile. It's simply testing that, rather than 
caring about the exact type of the elements.


--
  Simen


I see. Yes that makes sense. Thank you.


Re: questions around mutating range algorithms, const, and return ref

2018-01-29 Thread aliak via Digitalmars-d-learn

On Monday, 29 January 2018 at 06:46:26 UTC, Ali Çehreli wrote:
I think the following trivial wrapper around 
std.algorithm.remove() should do:


void removeMatching(R, N)(ref R r, N needles) {
import std.algorithm : remove, canFind;
r = r.remove!(e => needles.canFind(e));
}



Haha awesome! Yes that's much better :)

Note to self: learn to scroll down in the docs to find other 
definitions. I was convinced that remove only acted on indices :p



I'm not convinced that unfoundElements is needed at all. :)


Can't argue with that :)


> 6) It will not work when I pass in a range that has const
elements.
>
> ie:
>
> const(int)[] arr = [1, 2, 3, 4, 5];
> arr.pull([2, 3]);
>
> This I guess makes sense because moveEmplaceAll depends on
isInputRange
> and from my understanding, a const range cannot be one (is
that
> correct?).

Yes but your range is not const, the elements are. So, although 
const(int)[] is a range, it does not have mutable elements.


Ah right, yes the range is not const indeed.

You don't want to mutate const elements anyway. It would be 
breaking a promise that other parts of the program may be 
depending on. I would return a filtered-out range:


Right, I want to mutate the range though, not the elements. So 
moving things from one location is not considered as a const 
violation in c++ for eg, maybe the D way is different though? Any 
reading material there?


Also hasMobileElements!(const int[]) is true, so that means I can 
move elements around right?


If I can move elements, that means I should be able to move the 
ones I want to the beginning, of the range, but then I'm also 
unsure about how to go about changing the size of a range.


popBack on a mutable range with const data might cause 
destructors to be called, so I'm going to say that should be ok 
because as a user, if you're calling a range that mutates by 
removing things, and if you try and access those things later 
that's probably along the same lines as removing elements from a 
range that you're "foreach"ing over.


And your second approach is definitely more practical I'd say, 
but I'm going to go about this as a learning exercise in dealing 
with mutations, and const with ranges in D.


Thanks you for the comments!




Re: Lambda returning a lambda?

2018-02-01 Thread aliak via Digitalmars-d-learn

On Thursday, 1 February 2018 at 14:28:34 UTC, Simen Kjærås wrote:

--
  Simen


Ah, thank you both. For solution and explanation.

Me wonders... are there any thoughts around having functions 
return aliases as well? I have no idea if it's even possible but 
if it is, then does the initial syntax become possible? Or some 
kind of lazy type deduction that just tries to determine type 
when actually needed, and everything is an alias until that point?


Would a library curry solution on an alias lambda be possible?

alias f = curry!((a, b) => a * b) ?




Re: questions around mutating range algorithms, const, and return ref

2018-01-30 Thread aliak via Digitalmars-d-learn

On Monday, 29 January 2018 at 13:55:04 UTC, Seb wrote:

On Monday, 29 January 2018 at 11:36:26 UTC, aliak wrote:

On Monday, 29 January 2018 at 06:46:26 UTC, Ali Çehreli wrote:
I think the following trivial wrapper around 
std.algorithm.remove() should do:


void removeMatching(R, N)(ref R r, N needles) {
import std.algorithm : remove, canFind;
r = r.remove!(e => needles.canFind(e));
}



Haha awesome! Yes that's much better :)

Note to self: learn to scroll down in the docs to find other 
definitions. I was convinced that remove only acted on indices 
:p


Not too hard to fix: https://github.com/dlang/phobos/pull/6090


Nice! :D


Re: questions around mutating range algorithms, const, and return ref

2018-01-30 Thread aliak via Digitalmars-d-learn

On Monday, 29 January 2018 at 12:10:16 UTC, Simen Kjærås wrote:


Consider this case:

immutable(int)[] a = [1,2,3];
immutable(int)* b = [1];

You're free to slice the array or pop elements off its front or 
back, but if you change the order of elements, the value that b 
points to will change. D does not allow this.


You can create a new array with the elements moved into the 
locations you want, and with another layer of indirections 
(int*[]) you can move the elements of the array without 
mutating the values.


Ooh my... yes I can understand that. And I guess immutable is 
implicitly convertible to const and then if you can move const 
stuff then you have that problem. From the FAQ, my general 
understanding is that const is there as a bridge from immutable 
to mutable as a promise that the memory under this symbol will 
not be altered by that reference.


While experimenting a bit I came across this though which, 
currently, I do understand that value of


struct Int {
const int value;
}

void main() {
Int i0 = Int(0);
Int i1 = Int(1);
Int i2 = Int(2);
Int[3] arr0 = [i0, i1, i2];
Int[] arr1;
arr1 ~= i0;
arr1 ~= i1;
arr1 ~= i2;

arr1[0] = i0; // nope, Error: cannot modify struct arr1[0] 
Int with immutable members

}

So if a struct has a struct that has any member const, then 
effectively that whole struct is a const (well immutable it 
seems, so not even const)? Is that really correct? What is this 
sorcery? If yes I find it very surprising, but I don't think I'm 
very clear on what D is trying to solve with const ... yet.


I find const a little hard to swallow so far. From what I 
understand, it's good for function parameters, and as a function 
attribute for functions that return temporaries, except don't use 
it with ranges (i.e. don't put it on front). Actually not sure 
about function attributes on second thought. So... function 
parameters and local variables that you know won't change is what 
I'm going to go with for now.




Also hasMobileElements!(const int[]) is true, so that means I 
can move elements around right?


hasMobileElements checks if the value of front can be moved as 
in move constructors, not as in 'can be moved to a different 
spot in the range'. I will admit the name does little to 
unconfuse this point.


I'm not following here :s If value of front can be move 
constructed, then something can take it's place no?


Thank you!




free func "front" is not picked up as a candidate when doing range.front(...)

2018-02-07 Thread aliak via Digitalmars-d-learn
Hi, I'm trying to make a range.front free function that can be 
given a defaultValue. Doesn't seem to be working as is written 
below, seems like the compiler doesn't see the free function as a 
viable candidate. Isn't it supposed to do its UFCS wizardry and 
pick up the free func?


import std.stdio;

auto front(Range, T)(Range range, T defaultValue) {
import std.range: empty, front;
return range.empty ? defaultValue : range.front;
}

void main()
{
import std.range: iota;
0.iota.front(100).writeln;
// Error: inout method std.range.iota!(int, 
int).iota.Result.front is not callable using a mutable object


import std.algorithm: filter;
auto arr = [0, 1];
arr.filter!"true".front(99).writeln;
// Error: function 
std.algorithm.iteration.FilterResult!(unaryFun, 
int[]).FilterResult.front () is not callable using argument types 
(int)


arr.front(30).writeln; // OK

import std.range: front;
arr.front(30).writeln;
// Error: template std.range.primitives.front cannot deduce 
function from argument types !()(int[], int), candidates are: 
std.range.primitives.front(T)(T[] a) ...

}

Cheers


Re: free func "front" is not picked up as a candidate when doing range.front(...)

2018-02-08 Thread aliak via Digitalmars-d-learn
On Thursday, 8 February 2018 at 19:32:42 UTC, Jonathan M Davis 
wrote:
On Thursday, February 08, 2018 08:18:20 aliak via 
Digitalmars-d-learn wrote:

On Thursday, 8 February 2018 at 07:16:43 UTC, Jonathan M Davis

wrote:
> It would be a disaster if free functions could override 
> member functions. For starters, it would be impossible to 
> call the member function if that were allowed, whereas you 
> can always call a free function by not using UFCS. And in 
> general, it's far more desirable to have member function 
> functions override free functions, because then you can do 
> stuff like have have a range override find if it can provide 
> a more efficient implementation than std.algorithm.find.


That could be fixed with a precedence rule though no? Then 
member find will be preferred over free find. And it won't be 
impossible to call member functions.


That's exactly how it works now. If you call a function as if 
it were a member function, and that type has that member 
function, then it's that member function that gets called. If 
that type doesn't have that member function, then free 
functions are checked.


Wait no, that's not how it works now. Right now if a member 
function with the same name exists, then free functions are not 
even checked. Whereas if there's a precedence rule that prefers 
member functions, then free functions will still be checked if no 
member function with that name can be deduced as a viable 
candidate. How it is now disregards free functions without any 
consideration (if I've understood correctly), whereas I'm asking 
why free functions are not even considered if a member function 
is not an actual candidate. I'm not asking about overriding 
member functions with free functions.


i.e. in my original post, the free function front(int) does not 
exist in type FilterResult.


Cheers,
- Ali





Re: free func "front" is not picked up as a candidate when doing range.front(...)

2018-02-07 Thread aliak via Digitalmars-d-learn

On Wednesday, 7 February 2018 at 20:08:10 UTC, Paul Backus wrote:


You can only call a function with UFCS syntax if the object 
you're calling it with does not have a member with the same 
name as the function. Both iota's `Result` type and 
`FilterResult` have properties named "front", so you can't call 
your front function on them using UFCS syntax.


ahhh... bummer.

Do you know if it is a limitation that is yet to be implemented 
or one that will not (cannot?) be implemented and if so what the 
reason is?





Re: free func "front" is not picked up as a candidate when doing range.front(...)

2018-02-08 Thread aliak via Digitalmars-d-learn
On Thursday, 8 February 2018 at 07:16:43 UTC, Jonathan M Davis 
wrote:
It would be a disaster if free functions could override member 
functions. For starters, it would be impossible to call the 
member function if that were allowed, whereas you can always 
call a free function by not using UFCS. And in general, it's 
far more desirable to have member function functions override 
free functions, because then you can do stuff like have have a 
range override find if it can provide a more efficient 
implementation than std.algorithm.find.


That could be fixed with a precedence rule though no? Then member 
find will be preferred over free find. And it won't be impossible 
to call member functions.


Also, in this case where it's an overload, and not an override, 
it's very clear what should be called isn't it?


In the case of an override I "feel" it may indeed be a disaster, 
but not for the reasons you've stated above though, also not for 
any reasons I can think of :) Hijacking maybe? But then again, if 
I have a free function and then decide to make a member function 
I'm hijacking the free function... hmm.


Cheers




Re: free func "front" is not picked up as a candidate when doing range.front(...)

2018-02-11 Thread aliak via Digitalmars-d-learn
On Thursday, 8 February 2018 at 22:57:04 UTC, Jonathan M Davis 
wrote:
D tends to be very picky about what it puts in overload sets in 
order to avoid function hijacking - e.g. it doesn't even 
include base class functions in an overload set once you've 
declared one in a derived class unless you explicitly add an 
alias to the base class function in the derived class.


Also, D doesn't support "best match" with function overloads. 
The matches have to be exact - e.g. as soon as implicit 
conversions come into play, there can only be one match. If 
there's ever a conflict, you get a compilation error (unlike in 
C++, which tries to figure out what it thinks the best match is 
and go with that, sometimes with surprising results). And 
having both the member functions and free functions in the same 
overload set would basically require the compiler to go with 
the "best match," which simply isn't how D deals with 
overloads. Sometimes, that's annoying, but it also prevents a 
lot of subtle bugs that tend to crop up in C++ code.


https://dlang.org/spec/function.html#function-overloading 
https://dlang.org/articles/hijack.html


- Jonathan M Davis


Thanks for the articles, they shed a bit more understanding.

But I have some concerns/issues that maybe you or others can help 
out with a bit more.


First, the link on function-overloading says "The function with 
the best match is selected. " So I'm not sure what you mean about 
subtle bugs in C++ and D doesn't support best match. If you have 
foo(long), food(int) and call foo(3) in the same module, the best 
match is selected in D and in C++. But, anyway, ignoring C++ for 
now, after reading those articles you linked to my main issues 
are D related, not C++, let me try to explain:


The rules of resolving overload sets seem to be to resolve the 
issue where two overload sets have a matching function and one is 
silently better. This is understandable and makes sense.


The case of a free function not being considered if there is a 
member functions seems unrelated (as you say they are not part of 
the overload set, but it seems like like maybe they should be). 
In this case the member function does not match. If overload set 
resolution was applied the free function would be considered and 
be chosen as the only available candidate.


The rules for overriding, where functions with the same name in a 
base class are hidden, also make sense. But not relevant here. 
Infact, the hijacking article makes it seem to me that ufcs 
hijacking has maybe been overlooked? Consider two modules which 
are unrelated:


module a;

string f(R)(R r, int i) {
return "a.f";
}

string g(R)(R r) {
return "a.g";
}

-

module b;

auto algo() {
static struct R {
void popFront() {}
enum empty = false;
int front() { return 1; }
}
return R();
}

--
// Application programmer;

import std.stdio: writeln;
import a: f, g;
import b: algo;

void main(string[] args) {
auto r = algo();
auto a = r.f(3);
auto b = r.g;
writeln(a); // will print a.f
writeln(b); // will print a.g
}

All good so far. Until module b decides to add an internal 
function to it's R type:


auto algo() {
static struct R {
// Add a function
string g() { return "internal g"; }
}
return R();
}

Application programmer updates module b...

auto b = r.g; // Does not do what programmer thinks anymore, and 
no warnings.


Because a.g does not participate in overload set resolution 
rules, the application programmer has an unknown bug (is it just 
me or is this a bit... to put it lightly... scary?)


So that's the first problem. Then, secondly, say the people who 
make module b like using proper access control levels, and mark 
the internal string g() as private. Now there's a compiler error 
in the application programmer, with no real clues as to why, 
unless you deep dive in to D lang specs. And then you find out 
you're getting a compiler error because of a private, internal, 
function in a Voldermort type... ouch. Like. Big ouch. But ok, 
this can at least be worked around:


import a: f, c = g;

Now:

auto b = r.c; // ok.

Third problem:

Module b person adds another internal function to their type.

auto algo() {
static struct R {
// Add a function
string f() { return "internal f"; }
}
return R();
}

Now application programmer has a compile error again. Again with 
no clue. But this time it makes no sense because the line:


auto a = r.f(3);

Is clearly and unambiguously calling a.f(int). Again here if the 
free function was part of the overload set resolution rules, it 
would be resolved correctly.


Granted problem two and three are related. But there're subtle 
semantic difference there. Either this has been overlooked or 
there's a reason it is like this and must be like this that I've 
yet to hear.


As it is right now (someone correct me if I'm wrong), for someone 
who is writing 

Re: opUnary with ++ and -- on a struct that has a dynamic array

2018-02-12 Thread aliak via Digitalmars-d-learn

On Monday, 12 February 2018 at 06:16:21 UTC, rumbu wrote:

writeln(a++) translates to:

A copy = a;
a.opUnary!"++";
writeln(copy);

copy.a[] and a.a[] are the same reference, you increment 
a.a[0]/copy.a[0] in opUnary


to make this work you will need a postblit constructor:

struct A
{
   
   this(this)
   {
 a = a.dup; //make a copy a;
   }
}

In fact, you'll find exactly the same scenario in docs: 
https://dlang.org/spec/struct.html#struct-postblit




Ah! Awesome. Yes that works, thank you!

Cheers




Re: opCast cannot implicitly convert a.opCast of type X to Y

2018-02-13 Thread aliak via Digitalmars-d-learn

On Tuesday, 13 February 2018 at 12:12:30 UTC, Nathan S. wrote:

On Monday, 12 February 2018 at 02:05:16 UTC, aliak wrote:

struct B(T) {
T t;
}

struct A(T) {
T t;
auto opCast(U)() {
return B!U(cast(U)t);
}
}

void main() {
auto a = A!int(3);
auto b = cast(float)a; // error
}


Having the result of "cast(float) a" not be a float would be 
evil.


Ya :p dunno what I was thinking.


opCast cannot implicitly convert a.opCast of type X to Y

2018-02-11 Thread aliak via Digitalmars-d-learn
From spec: Cast expression: "cast ( Type ) UnaryExpression" 
converts UnaryExpresssion to Type.


And https://dlang.org/spec/operatoroverloading.html#cast makes no 
mention of the return type of opCast. One could think that the 
return type of opCast would be the return type. But it seems it 
must be the same as the template parameter of opCast else you get 
a compile error that seems like it can be much better.


---

import std.stdio;

struct B(T) {
T t;
}

struct A(T) {
T t;
auto opCast(U)() {
return B!U(cast(U)t);
}
}

void main() {
auto a = A!int(3);
auto b = cast(float)a; // error
}

Error: cannot implicitly convert expression a.opCast() of type 
B!float to float


Is this deliberate?

The use case I have is making an optional type that you can cast 
to a different type:


auto opCast(U)() const {
static if (isOptional!U)
{
alias V = OptionalTarget!U;
return empty ? no!V : some!V(cast(V)front); // it's a 
range so "front" is the raw value

}
else
{
return empty ? no!U : some!U(cast(U)front);
}
}

It would allow for scenarios like:

Optional!int a = 3;
auto b = cast(float)a;
// b == some!float


Cheers
- Ali


opUnary with ++ and -- on a struct that has a dynamic array

2018-02-11 Thread aliak via Digitalmars-d-learn

Hi,

Is there a way to get post increment and pre increment working 
properly in this scenario?


import std.stdio;

struct A {
int[] a;
this(int a) { this.a = [a]; }
auto opUnary(string op)(){
return A(mixin(op ~ "this.a[0]"));
}
}

void main() {
auto a = A(0);
int b = 0;
writeln(a++, ":", b++); // 1, 0 <-- wrong post increment 
result

writeln(++a, ":", ++b); // 2, 2
}

If I switch the order of the mixin expression (i.e. "this.a[0]" ~ 
op) then the pre increment does not work.


Any tips?

Cheers
- Ali


Re: opCast cannot implicitly convert a.opCast of type X to Y

2018-02-14 Thread aliak via Digitalmars-d-learn

On Wednesday, 14 February 2018 at 15:14:24 UTC, Meta wrote:


I think the best way to do this is to implement `map` for your 
optional type.


Optional!U map(U, alias f)()
{
return empty? no!U : some!U(f(t));
}

Optional!int a = 3;
auto b = a.map!(v => cast(float)v);
assert(is(typeof(b) == Optional!float));


Ooh yes, of course! Thank you :)




Re: opCast cannot implicitly convert a.opCast of type X to Y

2018-02-14 Thread aliak via Digitalmars-d-learn

On Thursday, 15 February 2018 at 00:34:33 UTC, Meta wrote:

On Thursday, 15 February 2018 at 00:27:40 UTC, Meta wrote:

On Wednesday, 14 February 2018 at 23:46:30 UTC, aliak wrote:

On Wednesday, 14 February 2018 at 15:14:24 UTC, Meta wrote:

Ooh yes, of course! Thank you :)


Even better:

import std.conv;

auto b = a.map!(to!float);


Actually, that won't quite work without redefining map a little:

Optional!U map(alias f, U = typeof(f(t.init)))()
{
etc...
}


Ah yes, true, also auto return would work. But then you'd still 
need to do the typeof(f(T.init)) evaluation in the body... plus 
you lose being able to see an explicit return type i guess... 
hmm. So nevermind :)


Though a free function would be good me thinks. Then you could 
use it seamlessly with std.algorithm.map.


Optional!U map(alias f, T, U = typeof(f(T.init)))(Optional!T opt)
{
return Optional!U(f(opt.t));
}

Cheers,
- Ali





Re: Trying to forward unwrapped opDispatch names to alias this

2018-02-19 Thread aliak via Digitalmars-d-learn

On Monday, 19 February 2018 at 01:00:23 UTC, Adam D. Ruppe wrote:

On Monday, 19 February 2018 at 00:42:05 UTC, aliak wrote:

struct B(T) {
T t;
A a;
alias a this;
auto opDispatch(string name)() if (hasMember!(T, name)) {
return mixin("t." ~ name);


Did you perhaps mean `A` instead of `T` here? cuz in your code 
T is int, not the struct.


I don't think I did :p

T is the wrapped type. So if T has a member (in the example it's 
the built in field "max") then forward that. If member not there 
then I figured the alias this would be used. I.e. in the example 
b.p should call A.p.


I assume this should work because rules for alias this (as I 
understand) are to basically try if there's a member name that 
resolves the call, else forward to alias this.


Trying to forward unwrapped opDispatch names to alias this

2018-02-18 Thread aliak via Digitalmars-d-learn
I have a scenario where I'm wrapping functionality for a type, 
but only if the contained type has a member. I want those to take 
precedence. If the member is not there, then I want to delegate 
to an aliases type via alias this.


I get an error here when I call b.p. Even though property p is in 
type A and there's an alias a this in B.


Anyway to do this?

struct A {
@property string p() {
return "A";
}
@property void p(string str) {}
}

struct B(T) {
T t;
A a;
alias a this;
auto opDispatch(string name)() if (hasMember!(T, name)) {
return mixin("t." ~ name);
}
}

void main() {
B!int b;
b.max.writeln;
b.p.writeln; // Error: no property 'p' for type 'B!int'
}

Cheers,
- Ali


Re: Trying to forward unwrapped opDispatch names to alias this

2018-02-20 Thread aliak via Digitalmars-d-learn

On Tuesday, 20 February 2018 at 11:27:23 UTC, Alex wrote:

There is a related ticket,
https://issues.dlang.org/show_bug.cgi?id=6434
However, not exactly facing this question.


Should that ticket be marked as resolved? The issue is for alias 
this to be considered before opDispatch but there were no 
arguments after giving reasons for that being a bad idea. And 
opDispatch is considered before (and disables alias this) now it 
seems?




It seems, that currently opDispatch replaces alias this... (?)
Nevertheless, not only T is the wrapped type, but also A with 
the alias.
What to do, if both members have a property with the same name? 
And why?


Good question, should it be dealt with in the same way as this is 
dealt with?


struct S {
void f() {writeln("S");}
}
struct A {
S s; alias s this;
void f() {writeln("A");}
}
A().f; // prints "A"

However, the above behavior seems dangerous maybe and could lead 
to silent bugs. I'm thinking if A.f was not defined, then A().f 
would print "S". But then someone comes along and defines an A.f 
and the user of A now gets different functionality without even 
knowing about it. Hrm.. one is not sure how one feels :p


But how about if they do not have the same name? Currently 
AliasThis says: "If the member is a class or struct, undefined 
lookups will be forwarded to the AliasThis member."


So opDispatch, even though it's constrained, is not considered 
undefined if it doesn't pass. In those cases should it not be 
forwarded to the alias this? If not, then why does a constrained 
function not qualify as being undefined if the constraint doesn't 
pass?


Consider:

struct A {
void defined() {}
}

struct B {
void opDispatch(string name)() if (name == "defined") {}
}

void main() {
A().defined; // ok
B().defined; // ok
A().undefined;
B().undefined;
}

Errors are:
* Error: no property 'undefined' for type 'A', did you mean 
'defined'?

* Error: no property 'undefined' for type 'B'

If you then define a struct S that contains a function named 
"undefined" and add a "S s; alias s this;" inside A and B, you 
get:


* Error: no property 'undefined' for type 'B'

But not for A. Shouldn't the behavior here be consistent? Or why 
not?


Churr,
- Ali




Re: Trying to forward unwrapped opDispatch names to alias this

2018-02-20 Thread aliak via Digitalmars-d-learn

On Tuesday, 20 February 2018 at 16:12:17 UTC, Adam D. Ruppe wrote:

On Monday, 19 February 2018 at 08:28:22 UTC, aliak wrote:
T is the wrapped type. So if T has a member (in the example 
it's the built in field "max") then forward that.


Oh, I see what you mean.

So the problem is that built in types don't have "members" per 
se, they have "magic". The built in properties don't count to 
`hasMember`. You could probably do `if(__traits(compiles, 
mixin("a." ~ member))` though.


I assume this should work because rules for alias this (as I 
understand) are to basically try if there's a member name that 
resolves the call, else forward to alias this.


yeah, just built in properties/members don't pass the same 
existence checks so that's confusing your template constraint.


I believe the same happens if it's not a built in property. You 
can replace B!int with B!S and have S contains a function "f" 
(for instance), then whether or the not constraint on opDispatch 
is:


__traits(compiles, mixin("t." ~ name))
or
hasMember(T, name)

You still get:

b.p.writeln; // Error: no property 'p' for type 'B!(S)'




Re: Converting array in to aliased tuple type.

2017-12-25 Thread aliak via Digitalmars-d-learn

On Monday, 25 December 2017 at 17:59:54 UTC, visitor wrote:

On Monday, 25 December 2017 at 15:03:08 UTC, aliak wrote:

On Monday, 25 December 2017 at 14:08:08 UTC, Mengu wrote:


I was kind of hoping for some magical D variadic alias 
template on Tuple or something that will just deconstruct the 
arguments in to tuple components.


i don't think it's better but :

https://run.dlang.io/is/2rgOzh


Heh, no it's probably not, but interesting! So it does work with 
a static array. Is it that .array on a range is not able to infer 
a size and hence produce a static array for the given situation? 
Is this a D limitation, a logical one or maybe just not 
implemented yet?


Cheers!


Re: std way to remove multiple indices from an array at once

2017-12-22 Thread aliak via Digitalmars-d-learn
On Thursday, 21 December 2017 at 15:59:44 UTC, Steven 
Schveighoffer wrote:

Here's a similar solution with an actual range:

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

Note, all done lazily. However, the indices must be 
sorted/unique.


-Steve


Noice! :D


Re: std way to remove multiple indices from an array at once

2017-12-21 Thread aliak via Digitalmars-d-learn
On Thursday, 21 December 2017 at 00:52:29 UTC, Nicholas Wilson 
wrote:
On Thursday, 21 December 2017 at 00:23:08 UTC, Steven 
Schveighoffer wrote:


I'm assuming here indices is sorted? Because it appears you 
expect that in your code. However, I'm going to assume it 
isn't sorted at first.


auto sortedIdxs = indices.assumeSorted; // also could be =

It's not going to be as good as hand-written code, complexity 
wise, but it's definitely shorter to write :)


-Steve
If indices is sorted with no duplicates and random access then 
you can do it in linear time.



Ah yes, I guess sorted and unique as well would be the expected 
input. But nice to see the handling of non-sorted indices.


I tried to search for an assumeUnique function as well (the 
assumeSorted one was nice to see) but it's not what I thought 
it'd be - seems to be more of an assumeUnaliased. And I guess 
there's no assumeUniqueElements.


And the filter approach is nice! :) (just need to account for the 
last ii++ (when filter comes back in I think one case would be ii 
== indices.length and you'd get a range error)


Thanks for the feedback!


std way to remove multiple indices from an array at once

2017-12-20 Thread aliak via Digitalmars-d-learn
Hi, is there a way to remove a number of elements from an array 
by a range of indices in the standard library somewhere?


I wrote one (code below), but I'm wondering if there's a better 
way?


Also, can the below be made more efficient?

auto without(T, R)(T[] array, R indices) if (isForwardRange!R && 
isIntegral!(ElementType!R) && !isInfinite!R) {

T[] newArray;
ElementType!R start = 0;
foreach (i; indices) {
newArray ~= array[start .. i];
start = i + 1;
}
newArray ~= array[start .. $];
return newArray;
}

// Usage
long[] aa = [1, 2, 3, 4]
aa = aa.without([1, 3])

Thanks!


Re: How do you safely deal with range.front?

2018-01-01 Thread aliak via Digitalmars-d-learn

On Monday, 1 January 2018 at 04:18:29 UTC, Ali Çehreli wrote:
If you're fine with specifying the function as a template 
argument, the following works. (As seen with 's => s.foo()' 
below, you have to use a lambda for member functions anyway.)


Ali


Nice! Thanks :) And I think your usage for something named 
"ifFront" actually makes more sense than using it to return 
"saferef" functionality.


I've basically implemented an optional type for now and the 
"iffront" implementation looks like this:


import std.range: isInputRange;

auto iffront(Range)(Range r) if (isInputRange!Range) {
import std.range: ElementType, empty, front;
import optional: no, some;
return r.empty ? no!(ElementType!Range) : some(r.front);
}

unittest {
import std.algorithm: filter;
assert([false].filter!"a".iffront.empty); // because optional 
is a range

}

unittest {
import std.algorithm: filter;
import optional: some, none;
struct A {
int f() {
return 7;
}
}

assert([A()].filter!"false".iffront.f == none);
assert([A()].filter!"true".iffront.f == some(7));
}

And thanks everyone for the input. I'll play around with some of 
the ideas and see what comes of it.





Re: How do you safely deal with range.front?

2018-01-01 Thread aliak via Digitalmars-d-learn

On Monday, 1 January 2018 at 02:18:36 UTC, Jonathan M Davis wrote:
Except that the reason for arrays throwing RangeErrors when you 
try and index them out-of-bounds is to avoid memory safety 
issues, which is not necessarily the case at all when you're 
talking about ranges. Having ranges in general be checking 
empty in front, popFront, back, etc. would add unnecessary 
overhead - especially when you consider that ranges often wrap 
other ranges. You'd be layering on check after check when the 
calling code is already supposed to be checking empty when 
necessary to make sure that the range isn't empty. You'd even 
be layering checks on top of the checks that arrays already do, 
since many ranges are ultimately wrapped around a dynamic array 
at their core.


[...]


Makes sense. Especially after pointing out that ranges are mostly 
arrays at the end. Thanks!




Re: static if and early exit from function doesn't seem to work?

2018-01-01 Thread aliak via Digitalmars-d-learn

On Sunday, 31 December 2017 at 13:47:32 UTC, Adam D. Ruppe wrote:

On Sunday, 31 December 2017 at 13:32:03 UTC, aliak wrote:
So it seems it tries to compile the statements below the check 
on V.length even though it's guaranteed to be true and there's 
a return statement inside the if.


Yeah, static if includes or excludes code independently at 
compile time.


So what you wrote there would be like, assuming the first to 
static ifs pass:


auto concat(R, V...)(R range, V values) if (isInputRange!R) {
import std.range: chain, ElementType;
return range;
return range.chain(values[0]).concat(values[1..$]);
}


The code is still there, even if it isn't reached due to an 
early return, and thus still must compile.


Using else static if means it won't be generated.


Ah ok, thanks! So it is intended behavior. I wonder if treating a 
return like a static else would be a good idea though. I at least 
can't see how it would break anything at this time.





Re: UCFS does not work for nested functions?

2018-06-18 Thread aliak via Digitalmars-d-learn
On Monday, 18 June 2018 at 19:26:47 UTC, Steven Schveighoffer 
wrote:

On 6/18/18 2:58 PM, aliak wrote:

[...]


It's the same in the fact that your call is silently switched 
to a different call. However, in the current syntax, an 
external entity CANNOT override a local function. When you call 
the nested function, it's the nested function, no matter what 
else occurs outside (even in the local module). There is no 
precedent for local functions to be overridden by module-level 
functions.


[...]


Ah I see. So it's basically that locals take priority, but if you 
allow them to UFCS then that's not true anymore because members 
need to take priority.


Ok yep, that makes sense. Thanks !


Can you tell if an template alias parameter is of a specific template?

2018-08-03 Thread aliak via Digitalmars-d-learn

Hi

Is there a way to tell if an alias is to a template?

I'm writing some algorithms and I need to distinguish between a 
binary predicate that provides "less than" and one that provides 
"equal to" semantics. So I have these two templates:


template eq(alias pred) {
alias eq = pred;
}

template lt(alias pred) {
alias lt = pred;
}

Then in some place:

static if (is(pred == eq)) {
  return eq(a, b);
} else static if (is(pred == lt)) {
  return !lt(a, b) && !lt(b, a); // equality with less than 
predicate

} else {
  // default assumptions about predicate
}

Then I can use it like:

auto a = S!(eq!((a, b) => a == b)) ;
auto a = S!(lt!((a, b) => a < b));

I've tried std.traits.TemplateOf and __traits(isSame and also 
variations of typeof and also traits.isInstanceOf. I wonder if I 
have to parameterize eq and lt over a compile time sequence 
instead?


Any tips to get this working?

Cheers,
- Ali


Re: How to get an inout constructor working with a template wrapper

2018-07-28 Thread aliak via Digitalmars-d-learn
On Friday, 27 July 2018 at 14:38:27 UTC, Steven Schveighoffer 
wrote:

On 7/27/18 9:29 AM, aliak wrote:
Ok, thanks to Simen from another post [0], I just figured out 
what the correct constructor and factory method for a template 
wrapper should be:


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

struct W(T) {
     T val;
     this(U : T, this This)(auto ref U val) {
     this.val = val;
     }
}

auto wrap(T)(auto ref T t) {
     return W!T(t);
}

Seems to catch all cases!


And instantiate a new template for all mutabilities. Whereas 
inout would only instantiate one (and disallows modification of 
val if not const or immutable).


-Steve


If you change the ctor to be inout then you get (from the link 
above):


onlineapp.d(4): Error: cannot implicitly convert expression val 
of type onlineapp.C to inout(C)
onlineapp.d(28): Error: template instance 
`onlineapp.W!(C).W.__ctor!(C)` error instantiating
onlineapp.d(4): Error: cannot implicitly convert expression val 
of type S1 to inout(S1)
onlineapp.d(44): Error: template instance 
`onlineapp.W!(S1).W.__ctor!(S1)` error instantiating
onlineapp.d(4): Error: cannot implicitly convert expression val 
of type onlineapp.C to inout(C)
onlineapp.d(9): Error: template instance 
`onlineapp.W!(C).W.__ctor!(C)` error instantiating

onlineapp.d(52):instantiated from here: wrap!(C)
onlineapp.d(4): Error: cannot implicitly convert expression val 
of type const(C) to inout(const(C))
onlineapp.d(9): Error: template instance 
`onlineapp.W!(const(C)).W.__ctor!(const(C))` error instantiating

onlineapp.d(53):instantiated from here: wrap!(const(C))

Am I applying inout incorrectly?


Re: How to avoid inout type constructor with Optional type wrapper undoing string type

2018-07-28 Thread aliak via Digitalmars-d-learn
On Friday, 27 July 2018 at 14:52:20 UTC, Steven Schveighoffer 
wrote:

On 7/23/18 2:39 PM, aliak wrote:

Hi,

I'm playing around with an Optional wrapper type. It stores a 
type T and a bool that defines whether a value is defined or 
not:


struct Optional(T) {
   T value;
   bool defined = false;
   this(U : T)(auto ref inout(U) value) inout {
     this.value = value;
     this.defined = true;
   }
}


Don't use inout here. The point of inout on the constructor is 
to *transfer* the mutability of the parameter to the struct 
instance. But you want to simply copy the type into the struct 
(an immutable(Optional!T) is quite useless, no?)


Just use U, not inout(U), and don't put inout on the 
constructor.


-Steve


But then it only works for mutable Optional right? Why would an 
immutable(Optional!T) be useless? Data can be "forever" empty or 
a certain value.


Re: How to get an inout constructor working with a template wrapper

2018-07-28 Thread aliak via Digitalmars-d-learn
On Friday, 27 July 2018 at 14:34:54 UTC, Steven Schveighoffer 
wrote:
The problem here is that inout(immutable(int)) is equivalent to 
immutable(int).


That is, all flavors of mutability are equivalent to 
immutable(int):


/*mutable*/(immutable(int)) => immutable(int)
  const(immutable(int)) => immutable(int)
  immutable(immutable(int)) => immutable(int)

So the compiler really looks at your wrap instantiation like 
this;


inout(W!(immutable(int))) wrap(immutable(int) t)


Ah ok, so the compiler remove inout behind me back here? (And 
then tells me it needs to be there? :p)




which triggers the (really bad) message.

I'd ask, why are you even worrying about explicit 
instantiation? Why not just wrap(3)?


Just because I don't see why it should not work really. Why not 
allow wrap!(immutable int)(3)?




or (if you really want to test it) wrap(immutable(int)(3))?



To make it compile successfully you can either:

1) Chance immutable to const, then it works for some reason.


Because immutable(const(int)) => immutable(int), so the 
compiler can't remove the inout behind your back.


2) Change the line to: "auto si = wrap(cast(immutable int)3);" 
- i.e. do not explicitly provide type information.


Yep, do this :)

Note that the point of inout is 2-fold:

1. reduce template instantiations. In fact, wrap!int works for 
const, mutable and immutable int.
2. ENSURE that the data isn't modified, even in the case of 
mutable parameters.


Thanks for the explanations! For some reason it's hard to get it 
all to *just work* right now without the template this. But it's 
probably some minor detail I'm just overlooking...




-Steve





Re: Disabling opAssign in a type disabled all the opAssigns of an aliased type?

2018-07-30 Thread aliak via Digitalmars-d-learn

On Monday, 30 July 2018 at 18:47:06 UTC, Alex wrote:

On Monday, 30 July 2018 at 18:30:16 UTC, aliak wrote:

Is this a bug?

If not is there a workaround?

I would like for the alias this to function as a normal A type 
unless B specifically disables certain features, but it seems 
weird that disabling one opAssign disables all of them inside 
the aliases type but not in the aliasing type?



struct A {
void opAssign(int) {}
}
struct B {
A a;
alias a this;
@disable void opAssign(float);
}

void main() {
B b;
b = 3;
}

Error: function `onlineapp.B.opAssign` is not callable because 
it is annotated with @disable


Cheers,
- Ali


What happens if you omit the @disable line?


Compiles ok then.


Re: Disabling opAssign in a type disabled all the opAssigns of an aliased type?

2018-07-30 Thread aliak via Digitalmars-d-learn

On Monday, 30 July 2018 at 20:20:15 UTC, Alex wrote:

On Monday, 30 July 2018 at 19:33:45 UTC, aliak wrote:

On Monday, 30 July 2018 at 18:47:06 UTC, Alex wrote:

On Monday, 30 July 2018 at 18:30:16 UTC, aliak wrote:

[...]


What happens if you omit the @disable line?


Compiles ok then.


So... is this a valid workaround? ;)


Hehe. Unfortunately not. It's for a proxy type that I need to 
disallow assignment to. But the proxy type uses alias to a T. So 
if T has a custom opAssign then bye bye functionality.


Disabling opAssign in a type disabled all the opAssigns of an aliased type?

2018-07-30 Thread aliak via Digitalmars-d-learn

Is this a bug?

If not is there a workaround?

I would like for the alias this to function as a normal A type 
unless B specifically disables certain features, but it seems 
weird that disabling one opAssign disables all of them inside the 
aliases type but not in the aliasing type?



struct A {
void opAssign(int) {}
}
struct B {
A a;
alias a this;
@disable void opAssign(float);
}

void main() {
B b;
b = 3;
}

Error: function `onlineapp.B.opAssign` is not callable because it 
is annotated with @disable


Cheers,
- Ali


Re: Disabling opAssign in a type disabled all the opAssigns of an aliased type?

2018-07-30 Thread aliak via Digitalmars-d-learn

On Monday, 30 July 2018 at 20:38:33 UTC, aliak wrote:

On Monday, 30 July 2018 at 20:20:15 UTC, Alex wrote:

On Monday, 30 July 2018 at 19:33:45 UTC, aliak wrote:

On Monday, 30 July 2018 at 18:47:06 UTC, Alex wrote:

On Monday, 30 July 2018 at 18:30:16 UTC, aliak wrote:

[...]


What happens if you omit the @disable line?


Compiles ok then.


So... is this a valid workaround? ;)


Hehe. Unfortunately not. It's for a proxy type that I need to 
disallow assignment to. But the proxy type uses alias to a T. 
So if T has a custom opAssign then bye bye functionality.


The actual code is here if you're curious:

https://github.com/aliak00/optional/pull/16/commits/93d51d790d313be3b108df2bd8b3699adc898bd0

Right now I've only:

@disable this(); // Do not allow user creation of a Dispatcher
@disable this(this) {} // Do not allow blitting either

But I also want to

@disable void opAssign(U)(Dispatcher!U)

So that you can't reassign to the Dispatcher (i.e. proxy type)

But if I do that then the opAssigns in the Optional!T cease 
functioning.




Re: How to avoid inout type constructor with Optional type wrapper undoing string type

2018-07-29 Thread aliak via Digitalmars-d-learn
On Sunday, 29 July 2018 at 12:30:58 UTC, Steven Schveighoffer 
wrote:

On 7/28/18 6:06 PM, aliak wrote:

[...]


What I meant was that string is actually mutable (the data 
isn't mutable, but the string can be re-assigned to another 
one), so Optional!string is more useful than 
immutable(Optional!(char[])). I shouldn't have said that 
immutable(Optional!T) is useless, you are right, and it 
wouldn't make sense for the defined flag to change there anyway.


[...]


Ah right. So it seems inout is removing head qualifiers on by-val 
parameters?


Filed what I think I understood from this:

https://issues.dlang.org/show_bug.cgi?id=19125


Re: Disabling opAssign in a type disabled all the opAssigns of an aliased type?

2018-07-30 Thread aliak via Digitalmars-d-learn

On Monday, 30 July 2018 at 20:54:28 UTC, Simen Kjærås wrote:

On Monday, 30 July 2018 at 18:30:16 UTC, aliak wrote:

Is this a bug?

If not is there a workaround?

I would like for the alias this to function as a normal A type 
unless B specifically disables certain features, but it seems 
weird that disabling one opAssign disables all of them inside 
the aliases type but not in the aliasing type?



struct A {
void opAssign(int) {}
}
struct B {
A a;
alias a this;
@disable void opAssign(float);
}

void main() {
B b;
b = 3;
}

Error: function `onlineapp.B.opAssign` is not callable because 
it is annotated with @disable



The workaround is to not disable opAssign. :p

Since this does work for other member functions that opAssign, 
I'm gonna say it's a bug - please file it in Bugzilla.


A perhaps better workaround than the above is to wrap A's 
opAssigns. Sadly, this can't be done with template mixins, 
since they don't overload with non-mixins. It can be done with 
string mixins, however. It's also possible to encapsulate all 
this in a nice little template:


struct A {
void opAssign(int) {}
void opAssign(float) {}
}
struct B {
A a;
alias a this;
@disable void opAssign(float);
mixin(wrap!(B, "opAssign"));
}

string wrap(T, string methodName)() {
enum targetName = __traits(getAliasThis, T)[0];
return `import std.traits : Parameters, ReturnType;
static foreach (e; __traits(getOverloads, 
typeof(`~targetName~`), "`~methodName~`"))
static if (!is(typeof({static 
assert(__traits(isDisabled, getOverload!(typeof(this), 
"`~methodName~`", Parameters!e)));})))

ReturnType!e `~methodName~`(Parameters!e args) {
return __traits(getMember, `~targetName~`, 
"`~methodName~`")(args);

}`;
}

template getOverload(T, string name, Args...) {
import std.traits : Parameters;
import std.meta : AliasSeq;
template impl(overloads...) {
static if (overloads.length == 0) {
alias impl = AliasSeq!();
} else static if (is(Parameters!(overloads[0]) == 
Args)) {

alias impl = overloads[0];
} else {
alias impl = impl!(overloads[1..$]);
}
}
alias getOverload = impl!(__traits(getOverloads, T, name));
}

unittest {
B b;
b = 3;
static assert(!__traits(compiles, b = 3f));
}

And that's enough magic for me for one night.

--
  Simen


Heheh  Amazing! In today's episode of extreme D (why is that 
not a thing?), we give you a "nice little template" :p


https://issues.dlang.org/show_bug.cgi?id=19130

Would it take much to fix it up to use with templated opAssigns 
as well?


I tried for a bit and got stuck with trying to get parameters and 
now I'm giving up for the time being.


struct A {
void opAssign(int) {}
void opAssign()(float) {}
}
struct B(T) {
A a;
alias a this;
@disable void opAssign(U)(B!U);

import std.traits : Parameters, ReturnType;
static foreach (t; __traits(getOverloads, A, "opAssign", 
true)) {

static if (is(typeof(t.stringof))) {
pragma(msg, t.stringof, " - ", Parameters!t);
} else {
pragma(msg, typeof(t), " - ", Parameters!t);
}
}
}

The Parameters!t of the template overloads all come out as "int" 
but only if there's the non-template opAssign(int) in A. If you 
remove that then you get errors. So something is fishy.


Also I realized that it's just 2 opAssigns in the aliased 
Optional!T type for my specific use case so maybe, err... copy 
pasta them in.


Cheers,
- Ali




  1   2   3   >