Re: Mixin template overloads not working

2021-12-07 Thread Q. Schroll via Digitalmars-d-learn

On Tuesday, 7 December 2021 at 12:43:40 UTC, Rumbu wrote:

Bug or feature?


Feature. It even has a name: "overload set". It keeps you from 
accidentally calling a function you had no idea existed, for 
example because of a name clash.



Is there any workaround?


Yes, the error message is very clear.



Re: Should this always work?

2021-05-03 Thread Q. Schroll via Digitalmars-d-learn

On Saturday, 1 May 2021 at 06:17:36 UTC, Mike Parker wrote:

On Saturday, 1 May 2021 at 04:55:10 UTC, frame wrote:
I always thought as long as an object implements an interface, 
it should be able to cast it from a void* if it really points 
to a supporting object.


No. An interface is like a pointer to a pointer.


Can you elaborate on this one? I don't really get it. Is an 
object handle also like a pointer to a pointer? (I feel like I 
can learn something here.)


Re: Is there a more elegant way to do this in D?

2021-04-11 Thread Q. Schroll via Digitalmars-d-learn

On Thursday, 8 April 2021 at 18:06:25 UTC, Meta wrote:

On Thursday, 8 April 2021 at 18:01:56 UTC, Meta wrote:

On Thursday, 8 April 2021 at 12:19:29 UTC, WebFreak001 wrote:


```d
string to01String(int[] x) @safe
{
auto conv = x.to!(ubyte[]); // allocates new array, so 
later cast to string is OK
conv[] += '0'; // assume all numbers are 0-9, then this 
gives the correct result

return (() @trusted => cast(string)conv)();
}
```


The @trusted lambda can also be replaced with 
[std.exception.assumeUnique](https://dlang.org/library/std/exception/assume_unique.html).


Never mind me, assumeUnique is @system (or at least it's 
inferred as @system), and anyway, you can't implicitly convert 
`immutable(ubyte)[]` to `immutable(char)[]`.


It has to be. It's not `@safe` quite obviously.


Re: Manually check struct invariants

2021-03-23 Thread Q. Schroll via Digitalmars-d-learn

On Tuesday, 23 March 2021 at 23:27:54 UTC, Paul Backus wrote:

On Tuesday, 23 March 2021 at 22:22:12 UTC, Q. Schroll wrote:
For a class object obj, one can use assert(obj) to get its 
invariants checked. How to do this for structs?


https://dlang.org/spec/expression.html#assert_expressions

If the first AssignExpression is a pointer to a struct 
instance for which a Struct Invariant exists, the Struct 
Invariant must hold.


So, you would write `assert()` for a struct instance.


I searched for it, but while for some reason, my brain read "If 
the first AssignExpression is a reference to a class instance for 
which a Class Invariant exists, the Class Invariant must hold." 
it failed to do so for the next sentence.


Thank you.


Manually check struct invariants

2021-03-23 Thread Q. Schroll via Digitalmars-d-learn
For a class object obj, one can use assert(obj) to get its 
invariants checked. How to do this for structs?


Compiler version "dirty"

2021-03-08 Thread Q. Schroll via Digitalmars-d-learn

When I enter `dmd --version`, it says:
  DMD64 D Compiler v2.095.1-dirty
What should the "dirty" mean? To me, it seems looks something 
went wrong somewhere.


Re: Why are multiple instances of the single enum created?

2021-02-01 Thread Q. Schroll via Digitalmars-d-learn

On Monday, 1 February 2021 at 11:39:26 UTC, Per Nordlöw wrote:

On Monday, 1 February 2021 at 11:37:49 UTC, Per Nordlöw wrote:
Ok, so then my follow-up question becomes, does the right hand 
sides of these two assignment share the same AST node? If not, 
why?


Because such a shared AST node could be potentially mutated in 
different ways in different contexts during its passes?


The spec says nothing about AST nodes. You can ask what DMD does 
(I don't know), but technically speaking, ASTs are an 
implementation detail of a compiler. A compiler need not have 
ASTs at all to follow the spec (unless the spec demands ASTs to 
exist, which I think it does not do). A compiler can change its 
AST nodes to a different yet equivalent representation without 
issue (unless the spec demands ASTs to exist and be of a certain 
form, which I think it does not do).


Re: Why are multiple instances of the single enum created?

2021-02-01 Thread Q. Schroll via Digitalmars-d-learn

On Monday, 1 February 2021 at 20:00:26 UTC, Q. Schroll wrote:

On Monday, 1 February 2021 at 09:40:20 UTC, Per Nordlöw wrote:

An enum only exists at compile-time, and does not occupy any
space. Each time it's referenced, a new instance of the value
is created. Why is that?


Short answer: An enum is a literal you can refer to by name. 
That's my mind-model for an enum.


I forgot to mention: An enum can have a precise type. As a stupid 
example, there are no first-class literals of type short or byte. 
But you can easily have short or byte enums. Also, the empty 
slice [] is typed void[] if you ask typeof([]); but an empty enum 
can be typed as any T[].


Re: Why are multiple instances of the single enum created?

2021-02-01 Thread Q. Schroll via Digitalmars-d-learn

On Monday, 1 February 2021 at 09:40:20 UTC, Per Nordlöw wrote:

An enum only exists at compile-time, and does not occupy any
space. Each time it's referenced, a new instance of the value
is created. Why is that?


Short answer: An enum is a literal you can refer to by name. 
That's my mind-model for an enum.


Long answer: If you use the literal "abc" twice, because it's 
underlying type is immutable (string == immutable(char)[]), the 
compiler can elide multiple allocations. But ['a','b','c'] has to 
be allocated each use. Basically, it lowers to a `new char[](3)` 
plus initialization.

It is completely irrelevant how the value has been determined.


Re: How to covert dchar and wchar to string?

2021-01-25 Thread Q. Schroll via Digitalmars-d-learn

On Monday, 25 January 2021 at 18:45:11 UTC, Rempas wrote:
Actually what the title says. For example I have dchar c = 
'\u03B3'; and I want to make it into string. I don't want to 
use "to!string(c);". Any help?


char[] dcharToChars(char[] buffer, dchar value)
{
import std.range : put;
auto backup = buffer;
put(buffer, value);
return backup[0 .. $ - buffer.length];
}

void main()
{
dchar c = '\u03B3';
char[4] buffer;
char[] protoString = dcharToChars(buffer, c);

import std.stdio;
writeln("'", protoString, "'");
}

Unfortunately, `put` is not @nogc in this case.



Re: How can I use UFCS for a loop

2021-01-25 Thread Q. Schroll via Digitalmars-d-learn

On Tuesday, 26 January 2021 at 00:47:09 UTC, Tim wrote:

Hi all,

How can I change the following to a more D-like approach by 
using UFCS?



double[3] result;


Unless you have a good reason, use a slice and not a static array:

double[] result;

The result of std.array.array will be a slice anyway.


Re: How can I use UFCS for a loop

2021-01-25 Thread Q. Schroll via Digitalmars-d-learn

On Tuesday, 26 January 2021 at 00:47:09 UTC, Tim wrote:

Hi all,

How can I change the following to a more D-like approach by 
using UFCS?



double[3] result;
Json json = res.readJson;
for(int i = 0; i < json.length; i++){
result[i] = json[i].to!double;
}


I'd prefer to do something like:


result = res.readJson[].map!(to!double);


Use std.array.array (alias: std.range.array) to make the range 
returned my map!(to!double) into an array.
Note that the result of map isn't actually evaluated until it is 
iterated. std.array.array will iterate and collect. 
https://dlang.org/phobos/std_array.html#array


result = res.readJson[].map!(to!double).array;

should work perfectly.




Re: How do I overload += operator?

2021-01-25 Thread Q. Schroll via Digitalmars-d-learn

On Monday, 25 January 2021 at 21:53:15 UTC, Jack wrote:

That naming is confusing


op: it is an operator method
Op: it takes an operator as a parameter
Assign: kinda obvious.

As an example, there are opIndex, opIndexAssign and 
opIndexOpAssign.

opIndex overloads obj[i].
opIndexAssign overloads obj[i] = rhs, and
opIndexOpAssign overloads opj[i] += rhs.

Maybe, in the greater scheme, the naming makes more sense to you.


Re: Variadic Struct Parameter

2021-01-12 Thread Q. Schroll via Digitalmars-d-learn

On Tuesday, 12 January 2021 at 18:44:53 UTC, Jonathan Levi wrote:

On Tuesday, 12 January 2021 at 17:46:14 UTC, Q. Schroll wrote:
It's obvious why arrays work, it's the primary use case. I 
have no idea why classes are allowed. That classes are 
allowed, but structs are not, makes no sense to me.


I like the variadic feature for classes, but I wish it worked 
for structs as well, given that structs are value types on the 
stack anyway, the same assembly could have either signature 
(assuming matching argument/struct ordering).


But why does this compile?

```
struct S {/*...*/}

void fun(S s...) {/*...*/}
```
If structs do not work as variadic parameters, why does `fun` 
still compile?


Because D does allow you to specify things that have no effect. 
People sometimes complain about this as nonsense, but it has its 
merits in meta-programming:


void fun(T)(T t...) { }

Here, if T is a class or array type (including static arrays, 
btw), the dots have an effect, otherwise not. It would be 
unnecessary to require a split on the basis what T is.


Re: properly passing strings to functions? (C++ vs D)

2021-01-12 Thread Q. Schroll via Digitalmars-d-learn

On Monday, 11 January 2021 at 16:53:50 UTC, IGotD- wrote:
I usually use "const string text" because D has no implicit 
declaration of variables. So using "ref" will not create a 
variable. This is contrary to C++ where passing as "const 
std::string " has a performance benefit and also C++ 
creates a unnamed variable for you.


Did you consider `in`? It will do that in some time and do it now 
with -preview=in.
If you're using `const`, in almost all cases, `in` will work, 
too, and be better (and shorter).


Re: properly passing strings to functions? (C++ vs D)

2021-01-12 Thread Q. Schroll via Digitalmars-d-learn

On Monday, 11 January 2021 at 14:12:57 UTC, zack wrote:
A beginner question: How to pass strings properly to functions 
in D?
Is there any allocation going on if just use a function as 
"myPrint"? In C++ I have often seen calls where one just passes 
a reference/const reference to a string to avoid allocation.


C++:
void myPrintCPP(const std::string& input){ ... }

D:
void myPrint(string text){ ... }
void myPrintRef(ref string text) { ... }


In D, `string` is an abbreviation for the type immutable(char)[], 
i.e. slice of immutable char. The slice type is a pointer+length 
pair, a (T*, size_t) tuple, it is very lightweight. Using `ref 
T[]` (that includes `ref string` aka `ref immutable(char)[]` is 
the way if you want reassignments or expanding/shrinking of the 
array to be visible to the caller. Since the cost of copying a 
pointer and a length is very low, I'd just use this:


  void myPrint(string text) { ... }

It'll be probably what you want. Since you cannot write the 
immutable characters, if you don't intend to reassign, expand, or 
shrink the string locally, you can use `in string text`.
You can basically only read `in` parameters for information. What 
`in` buys you is that the compiler will figure out the best way 
to pass the object. C++'s const T& will reference always, which 
is worse than a copy for small types. D's `in` will copy if the 
compiler thinks it's cheaper than referencing. Give 
https://dlang.org/changelog/2.094.0.html#preview-in a read, if 
you want details about `in`. Use it when it applies. It also 
documents intent.


Re: Variadic Struct Parameter

2021-01-12 Thread Q. Schroll via Digitalmars-d-learn

On Tuesday, 12 January 2021 at 17:26:15 UTC, Jonathan Levi wrote:

Why is this not working?

```
struct S {
int x;
string y;
}

void fun(S s ...) {


This is intended for arrays and classes, not structs. Using ... 
for something other than arrays and c



fun(S(5,"hi"));


That one should compile...


fun(5,"hi");


and the second one not.

It's obvious why arrays work, it's the primary use case. I have 
no idea why classes are allowed. That classes are allowed, but 
structs are not, makes no sense to me.


Re: [Understanding] Classes and delegate inheritance vs function pointers

2021-01-09 Thread Q. Schroll via Digitalmars-d-learn

On Saturday, 9 January 2021 at 21:57:43 UTC, sighoya wrote:

On Saturday, 9 January 2021 at 20:20:38 UTC, Q. Schroll wrote:
That's not what I mean. You copy the reference. That's not 
what referencing meant.


  Derived d = new Derived();
  Base* bp =  // fails
  const(Base) cbp =  // compiles.


Generally, allowing covariant assignment for the Ptr, i.e. 
T*, type only in case of const T* strikes me. IMHO, both should 
be synchronously (dis)allowed.


I'm unsure what you mean.

If you have an array `cars` of type Car[], you can treat it as a 
const(Vehicle)[] because reading a Car as a Vehicle is 
unproblematic. But if it could bind to Vehicle[], its elements 
could be written arbitrary Vehicles. Say it worked, then:


  Car[] cars = ...;
  Vehicle[] vehicles = cars;
  vehicles[0] = new Boat; // err...
  // cars[0] is a Boat now!?

Now what? Do what Java does and throw an Exception? Or use const 
to prevent mutation?


Because D doesn't support co(ntra)variance, it should be both 
disallowed?


Imagine for a moment, `const` were named `read_only` and there 
were a specifier `write_only`. That looks silly, but makes sense 
in some cases:


  Vehicle[] vehicles = ...;
  write_only(Car)[] cars = vehicles; // WTF!?
  cars[i] = new Car; // wait, that's actually okay...

Because write_only isn't a thing in D, contravariance is an odd 
thing to get your a D mind around.


Otherwise, because D already support the const case, why not 
the non const case?


The non-const case makes no sense.


Are there any alignment issues supporting the non const case?


It's not alignment, probably. (Maybe it is, I know almost nothing 
about alignment, to be honest.) Among other things, in the 
non-const case, as you call it, the type system cannot guarantee 
anymore that stuff that is typed some way actually contains those 
objects.
It is one of the major issues Java has and why everyone and their 
mom tells you not to use Java's arrays and instead use List or 
similar well-behaved constructs.


BTW, my question wasn't about classes at all. I used them as an 
illustration what works and asked why (seemingly) the same thing 
doesn't with function pointers.


Re: [Understanding] Classes and delegate inheritance vs function pointers

2021-01-09 Thread Q. Schroll via Digitalmars-d-learn

On Saturday, 9 January 2021 at 20:00:35 UTC, Jacob Carlborg wrote:

On 2021-01-09 19:16, Q. Schroll wrote:

Say I have a class hierarchy like this:
   class Base { }
   class Derived : Base { }
A Derived object cannot be referenced as a Base object, but as 
a const(Base) object. That makes sense to me.


It can:

Base b = new Derived();


That's not what I mean. You copy the reference. That's not what 
referencing meant.


  Derived d = new Derived();
  Base* bp =  // fails
  const(Base) cbp =  // compiles.


Is there a reason all you're examples are using pointers?


Yes. Actually, I need it for slices, but only pointer part of it 
really mattered.


A Derived[] is implicitly a const(Base)[], not a Base[].
A void delegate() @safe[] is implicitly a const(void 
delegate())[].
But it seems a void function() @safe[] **isn't** implicitly a 
const(void function())[].


Functions taking those are kind of useless like that.


[Understanding] Classes and delegate inheritance vs function pointers

2021-01-09 Thread Q. Schroll via Digitalmars-d-learn

Say I have a class hierarchy like this:
  class Base { }
  class Derived : Base { }
A Derived object cannot be referenced as a Base object, but as a 
const(Base) object. That makes sense to me.


One can replace Base by a @system delegate type (SysDG) and 
Derived by a @safe delegate type (SafeDG) and it works the same 
way: a SafeDG object cannot be referenced as a SysDG object, but 
as a const(SysDG) object.


However, if I try that with function pointers instead of 
delegates (SysFP, SafeFP), for some reason, a SafeFP cannot be 
referenced as a const(SysFP).
This makes no sense in my head. Is there some reason I'm unable 
to see?


Example code is here: https://run.dlang.io/is/zSNArx


Re: Alias woes

2020-12-17 Thread Q. Schroll via Digitalmars-d-learn

On Saturday, 12 December 2020 at 01:02:56 UTC, SealabJaster wrote:

Please see this shortened snippet: https://godbolt.org/z/j8f3x5

I've ran into annoyances before when using aliases to member 
fields, but something subtle like this was rather annoying to 
figure out.


Why does the compiler feel the need to embed a context pointer 
anytime you provide an to alias a member?


In my case the function was also writing seemingly garbage 
values into the .ptr and .length fields for the ref'd string, 
but it doesn't seem to happen in the godbolt snippet.


Bonus, a pet peeve of mine: https://godbolt.org/z/bnK91f


I don't have an answer, but aliasing non-static fields outside 
the struct isn't something one does often. This is probably a bug.


Re: Avoid deallocate empty arrays?

2020-12-17 Thread Q. Schroll via Digitalmars-d-learn

On Thursday, 17 December 2020 at 16:11:37 UTC, IGotD- wrote:

It's common using arrays for buffering


Outside of CTFE, use an Appender.¹ Unless you're having a 
const/immutable element type, Appender can shrink and reuse 
space.² If you have, reallocation is necessary anyway not to 
break const/immutable' guarantees.


¹ https://dlang.org/phobos/std_array.html#appender
² https://dlang.org/phobos/std_array.html#.Appender.clear


Re: UFCS functions with both pointers and refs

2020-12-17 Thread Q. Schroll via Digitalmars-d-learn

On Tuesday, 15 December 2020 at 20:38:04 UTC, Dave P. wrote:
The use case would be to define extension methods on a struct 
outside of where the struct is defined. The extension method 
mutates the state of the struct, so I want to ensure I am 
modifying the original struct and not a copy. If it’s a method 
and I call it on a pointer to the struct, the pointer will get 
auto-dereferenced and everything is great. So my question is 
that if I want an extension method as a free function, do I 
have to write both the version whose first argument is a 
pointer to the struct and the version whose first argument is a 
ref, or is there some keyword or other technique so that the 
pointer gets auto-dereferenced the same way as if it were a 
method. It sounds like the answer is no and I have to write a 
version that just dereferences the pointer and calls the ref 
version.


Now it's coming together.

The easiest way to do this is using an overload taking a `ref` 
(non-pointer) value and another taking a pointer (by copy, I 
guess).


R f(ref T value, Ts args) { /* doing the actual work */ }
R f(T* ptr, Ts args) { f(*p, args); } // manually dereference

You cannot get around doing the actual `f`, and the addition 
isn't that big. I think that's the best solution unless you have 
to deal with non-copyable types among Ts. Then you need to 
forward those properly.
I couldn't really do better using one template instead of this 
simple overload. (Certainly a template can be made, but it is 
clearly not the better solution.)


Re: closures + struct: Error: forward reference to inferred return type of function call

2020-12-15 Thread Q. Schroll via Digitalmars-d-learn

On Monday, 14 December 2020 at 14:39:14 UTC, ddcovery wrote:

On Monday, 14 December 2020 at 12:22:26 UTC, ddcovery wrote:

int opCmp(Number other){
  return _value - other.value;
};

Correction:

bool opEquals(Number other){
  return _value == other.value;
};


You could just give the struct a variable and use that instead of 
the enclosing function's parameter:


https://run.dlang.io/is/4Lqf15

Then, the struct can actually be static.


Re: UFCS functions with both pointers and refs

2020-12-15 Thread Q. Schroll via Digitalmars-d-learn

On Sunday, 13 December 2020 at 19:02:34 UTC, Dave P. wrote:

On Sunday, 13 December 2020 at 18:44:20 UTC, Mike Parker wrote:

On Sunday, 13 December 2020 at 18:31:54 UTC, Dave P. wrote:
Do I have to write both and have one forward to the other for 
more

complicated functions?


For free functions, yes.


Is there any way to write the function as a template that is 
generic over a parameter being a pointer or a reference, but 
does not allow passing a copy?


I'm not sure what you mean by a reference. D doesn't have 
references in general, only class references that are just 
glorified pointers. There are also `ref` parameters, but those 
aren't generally referred to as "references" and are inside the 
function almost indiscernible from non-ref parameters. So, I'll 
ignore that.


Copying only takes place under one circumstance: When an lvalue 
is passed to a function that does not take that argument by 
`ref`. So one possibility is to just define that overload and 
@disable it. You don't even need a template for this:


void f(X x); // matches lvalues and rvalues
void f(ref X x); // matches lvalues only

The latter is a better match than the former for lvalues. 
@disable'ing it will do the job. On the other hand, not 
@disable'ing it will make `f` work with any argument by moving 
rvalues to the former overload and referencing lvalues using the 
second one.


On templates, those can be unified by slapping `auto ref` before 
the parameter. You can also use `auto ref` (which infers `ref` 
from the passed argument) and check it with an `if` template 
constraint:


void f(T)(auto ref T arg)
if (!__tratis(isRef, arg)) // only accepts non-ref args
{ /* your code here */ }

The constraint can easily be flipped.


Re: Why can I call a function with mismatched parameter type?

2020-12-11 Thread Q. Schroll via Digitalmars-d-learn
On Friday, 11 December 2020 at 11:32:09 UTC, rikki cattermole 
wrote:
string is not a built in type. It is an alias defined by 
druntime.


https://github.com/dlang/druntime/blob/master/src/object.d#L35

int on the other hand is defined by the compiler. It 
understands it.


It doesn't magically understand it. `int` is a keyword and thus 
not a legal identifier.
From a grammar perspective, in `(x, y) { }`, x and y are parsed 
as types. [1] However, in lambda expressions, when there's a type 
only and no parameter (according to the grammar) given, the 
compiler treats a single identifier as a parameter with inferred 
type. Since `int` is not an identifier, but a keyword, that 
treatment does not happen. As you explained correctly, `string` 
is merely an identifier and thus seen as a parameter name.


[1] https://dlang.org/spec/grammar.html#Parameters


Re: Pass enum variable as const ref arg

2020-12-08 Thread Q. Schroll via Digitalmars-d-learn

On Friday, 4 December 2020 at 12:54:25 UTC, Andrey wrote:

[...]
WTF?


If you come from a C or C++ background, it's quite reasonable to 
think of enum stuff like a #define macro. You're using static 
arrays, but note that array literals allocate in many use cases. 
It really is like a C/C++ macro. Use n times = allocate n times. 
You avoid that with a static immutable completely. That said, if 
you use the value of that enum only at compile-time, there's no 
need for a static immutable.


Hope that this rule of thumb sheds some more light on how to 
achieve certain stuff.


Re: Anybody know if I can build DMD with Visual Studio 2019?

2020-12-04 Thread Q. Schroll via Digitalmars-d-learn

On Friday, 4 December 2020 at 09:32:29 UTC, Imperatorn wrote:
On Wednesday, 2 December 2020 at 22:37:06 UTC, WhatMeWorry 
wrote:
It works now.  Not sure what I did to _not_ make it work 
yesterday.


That's easy. You made a post here about it and the universe got 
scared.


This made my day.


Re: How to unit-test a phobos module?

2020-11-26 Thread Q. Schroll via Digitalmars-d-learn

On Thursday, 26 November 2020 at 05:29:16 UTC, Mike Parker wrote:
On Wednesday, 25 November 2020 at 21:36:36 UTC, Q. Schroll 
wrote:




[1] https://wiki.dlang.org/Building_under_Windows


You might try Digger. That will hide all the tedious bits.

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


I think using digger in principle works and I assume the problems 
I got aren't Digger's fault, but ae's. Building DMD + DRuntime 
failed.


In my working folder (created by DUB running Digger), there's 
DMD.exe, but trying compiling anything results in "Error: cannot 
find source code for runtime library file 'object.d'"


I did nothing but follow the instructions on 
code.dlang.org/packages/digger :


dub fetch digger
dub run digger -- build

I tried building the current version v2.94.2 and tried 
--model=64, nothing helped.


The error I'm presented is when

   work\build\bin\dmd.exe -lib -ofphobos64.lib -Xfphobos.json 
-conf= -m64 [..1]

   -I../druntime\import std\stdio.d [..2]


is executed.
[..1] IMO unrelated options
[..2] following many more std modules, probably all that there 
are (haven't checked)


The error message is:
std\stdio.d(16): Error: module stddef is in file 
'core\stdc\stddef.d' which cannot be read


I have no idea why the import failed. The stdc subfolder isn't in 
the core folder, but that core folder isn't even in a 
druntime/import folder anyway. Something's going horribly wrong.


It seems something beyond us just doesn't want me to get D stuff 
done. :(


Tomorrow, I'll try setting up a dual boot and give it a shot 
there. (Not the dub experience  but following 
https://wiki.dlang.org/Building_under_Posix)


Thank you all for your answers.


Re: How to unit-test a phobos module?

2020-11-25 Thread Q. Schroll via Digitalmars-d-learn

On Wednesday, 25 November 2020 at 21:57:12 UTC, H. S. Teoh wrote:
On Wed, Nov 25, 2020 at 09:49:12PM +, Paul Backus via 
Digitalmars-d-learn wrote:
On Wednesday, 25 November 2020 at 21:16:06 UTC, Q. Schroll 
wrote:
> On Wednesday, 25 November 2020 at 21:11:24 UTC, Paul Backus 
> wrote:
> > On Wednesday, 25 November 2020 at 20:58:20 UTC, Q. Schroll 
> > wrote:

> > > My setup:
> > > * A fresh DMD installed a few minutes ago.
> > > * Clone of my Phobos fork with up-to-date changes from
> > > dlang/phobos/master.
> > 
> > Do you have clones of dmd and druntime too?
> 
> Why would I need those? I haven't needed them back then.


copyEmplace isn't in druntime 2.094.2.


My guess is that the problem is caused by trying to compile 
Phobos with a compiler that uses an incompatible version of 
druntime.


One of the issues is, I don't know what DRuntime really is. As 
far as I understand on the surface-level, it's functionality one 
would expect to be implemented by the compiler, but actually 
implemented in plain D code. A low-level Phobos if you want. So 
I'm a little confused why there's even a need for it to be 
"built". Isn't it "just code" like Phobos?


I'm increasingly frustrated because, honestly, it seems I don't 
know enough about the build processes or build tools used. The 
Wiki expects Digital Mars make to be there, also says explicitly 
not to confuse it with GNU make, but in my DMD folder there is 
none. Since it's a plain install, I suspect the Wiki is outdated. 
How am I expected to figure things out? It seems like everyone 
else knows how to do it, just I'm too stupid.



*ME* Why would I need those? I haven't needed them back then.


I wrote that not saying "do the work for me, guys" but "please 
tell me what changed".


Re: How to unit-test a phobos module?

2020-11-25 Thread Q. Schroll via Digitalmars-d-learn
On Wednesday, 25 November 2020 at 21:16:15 UTC, Steven 
Schveighoffer wrote:

I typically do:

make -f posix.mak std/.test

-Steve


For some reason, [1] says `make.exe` would be installed by the 
DMD installer, but I found none. It explicitly says not to use 
GNU make. (I'm on Windows.)


[1] https://wiki.dlang.org/Building_under_Windows


Re: How to unit-test a phobos module?

2020-11-25 Thread Q. Schroll via Digitalmars-d-learn

On Wednesday, 25 November 2020 at 21:11:24 UTC, Paul Backus wrote:
On Wednesday, 25 November 2020 at 20:58:20 UTC, Q. Schroll 
wrote:

My setup:
* A fresh DMD installed a few minutes ago.
* Clone of my Phobos fork with up-to-date changes from 
dlang/phobos/master.


Do you have clones of dmd and druntime too?


Why would I need those? I haven't needed them back then.


How to unit-test a phobos module?

2020-11-25 Thread Q. Schroll via Digitalmars-d-learn
When trying to unit-test an unchanged phobos module from 
phobos/master, I get errors such as


module core.lifetime import copyEmplace not found

and template instantiation errors. What is the correct arguments 
to pass to (r)dmd? I know it worked for me some years ago, but 
somehow, it doesn't work now.


I've looked at [1], [2], [3] which didn't work (maybe outdated?). 
How do you do it and what am I doing wrong?


My setup:
* A fresh DMD installed a few minutes ago.
* Clone of my Phobos fork with up-to-date changes from 
dlang/phobos/master.


In the clone's folder, ~/dlang/phobos, I tried the following 
commands:


$ dmd -main -unittest -version=StdUnittest -I. -run 
std/.d


and

$ rdmd -main -unittest -version=StdUnittest -I. std/.d

I have the feeling I'm missing something quite obvious.

[1] 
https://wiki.dlang.org/Contributing_to_Phobos#Test_a_single_Phobos_module
[2] 
https://wiki.dlang.org/Building_under_Windows#Building_Phobos_2

[3] https://github.com/dlang/phobos/blob/master/CONTRIBUTING.md


Re: static alias this and if/do/while/for

2020-10-26 Thread Q. Schroll via Digitalmars-d-learn
On Thursday, 22 October 2020 at 21:55:59 UTC, Jack Applegame 
wrote:

There is a funny feature (or bug) in the D language:

static alias this and static operator overloading.

For example


interface Foo {
static {
int value;
void opAssign(int v) { value = v; }
int get() { return value; }
alias get this;
}
}


Now we can use type Foo as if it were an lvalue/rvalue:


Foo = 5;
int a = Foo;
int b = Foo + a;


I heavily use this feature in my MCU library.


It doesn't surprise me that much. What actually did was that 
static opIndex() works. Consider this:


struct X
{
static int opIndex() { return 1; }
}

alias SliceOf(T) = T[];
enum ValueOf(T) = T[];

static assert( ! is(int[SliceOf!X] == int[ValueOf!X]));

But static opIndex and friends can be useful: 
https://run.dlang.io/is/s15zS0 I'd actually find it awesome if we 
had opCallAssign and opCallOpAssign; the reason I used opIndex 
and not opCall is that way, one gets access to the right-hand 
side and to-assign parameters by reference, so no internal 
pointer stuff's needed.



But it doesn't work inside conditionals:


if(Foo) {}// Error: type Foo is not an expression
while(Foo) {} // Error: type Foo is not an expression


Even if we define `static opCast!bool()`. It doesn't help.


Only using Foo.opCast!bool works; cast(bool) won't compile.


Should this be fixed?


The bool stuff should be fixed. The other direction would be a 
breaking change.


Re: Why is there no range iteration with index by the language?

2020-06-09 Thread Q. Schroll via Digitalmars-d-learn

On Wednesday, 10 June 2020 at 00:53:30 UTC, Seb wrote:
It's a bit more complicated though as you need to avoid subtle 
breakage with ranges that return tuples that are auto-expanded 
like e.g. `foreach (k,v; myDict)`.


Okay, I can accept that. It's a poor decision, but well, it is 
what it is.


Anyhow, I would be highly in favor of DMD doing this. It's one 
of those many things that I have on my list for D3 or a D fork.


Is there any "official" or at least public list for D3 
suggestions?

Many people here talk about it recently...


Why is there no range iteration with index by the language?

2020-06-09 Thread Q. Schroll via Digitalmars-d-learn
Is there any particular reason why std.range : enumerate is a 
thing and


foreach (i, e; range) { ... }

doesn't work from the get-go? I wouldn't have such an issue with 
it if static foreach would work with enumerate just fine. As far 
as I can tell,


foreach (e; range) { ... }

is being lowered to

for (auto _range = range; !_range.empty; _range.popFront)
{
auto e = _range.front;
...
}

So why cant DMD rewrite

foreach (i, e; range) { ... }

to

for (auto _range = range, index = size_t(0); !_range.empty; 
_range.popFront, ++index)

{
size_t i = index;
auto e = _range.front;
...
}

Doesn't seem like a big deal, does it? I'm asking because I 
suspect there's an odd reason I have no idea and I whish to be 
educated.


Re: How to port C++ std::is_reference to D ?

2020-06-06 Thread Q. Schroll via Digitalmars-d-learn

On Wednesday, 13 May 2020 at 13:36:14 UTC, wjoe wrote:

On Monday, 11 May 2020 at 19:08:09 UTC, Q. Schroll wrote:

[...]

1. You can have variables ("data members") of reference type 
in structs. (They work like head-const pointers; if D had 
head-const or at least head-const pointers, those would be 
practically the same, only that references cannot be null.)

[...]



That's also something I don't really know how to correctly port 
to D.
Anyways, that was insightful. Thank you very much for your 
explanations.


Another thing that just occurred to me is generating types. Say I 
have an AliasSeq of types. I want to generate a list of delegates 
taking all of them with all combinations of `ref`ness. Example:

alias list = AliasSeq!(int, char, double);
I want the AliasSeq

alias delegates = AliasSeq!(
R delegate(int, char, double),
R delegate(ref int, char, double),
R delegate(int, ref char, double),
R delegate(int, char, ref double),
R delegate(ref int, ref char, double),
...,
R delegate(ref int, ref char, ref double)
);

That would be way easier if `ref` were part of the type (like 
const/immutable/inout/shared are).


Re: Fastest way to check using if identifier has already been defined, using static if or similar?

2020-06-04 Thread Q. Schroll via Digitalmars-d-learn

On Thursday, 4 June 2020 at 09:03:40 UTC, Simen Kjærås wrote:

string exists(string s) {
return "__traits(compiles, { mixin(\"alias _ = "~s~";\"); 
})";

}


Little nitpicking, but D has many forms of string literals. 
Escaping is hard to read especially without syntax highlighting. 
Escaping to me is an old hack C did we shouldn't really use.


string exists(string s) {
return `__traits(compiles, { mixin("alias _ = ` ~ s ~ 
`;"); })`;

}

The _ as a name, to me, proves that a __traits(freshName), that 
returns a string that is distinct from every symbol name visible 
from the point it's defined,  would be useful in these occasions. 
Because if someone used _ as an identifier in a context where the 
`exisits` function is used, it might fail.




Re: Is this a good tree?

2020-06-02 Thread Q. Schroll via Digitalmars-d-learn

On Tuesday, 2 June 2020 at 11:44:10 UTC, Vladimirs Nordholm wrote:

Hello.

I want to create a tree which maps sequences of numbers to 
data. ex:

- [1, 2]-> 1
- [1, 3, 1] -> 2
- [1, 3, 2] -> 3

I have no prior knowledge of what makes a good tree, and I am 
unsure if what I've got is good. I mean it works, but if anyone 
with more knowledge of trees or D-lang would mind giving some 
feedback I would be more than happy.


I've made a scaled-down, "in essence", runnable example of what 
I have here: https://run.dlang.io/is/JI8T2T


For more context, my actual code (with extra boilerplate + 
project specific things) can be found here: 
https://github.com/vladdeSV/scone/blob/develop/source/scone/os/posix/input/input_tree.d


Once again, any feedback is greatly appreciated.


You might want to check out this: 
https://en.wikipedia.org/wiki/Trie


Possibly, that's exactly what you're looking for.


Re: How to port C++ std::is_reference to D ?

2020-05-11 Thread Q. Schroll via Digitalmars-d-learn

On Saturday, 9 May 2020 at 13:44:27 UTC, Per Nordlöw wrote:

On Wednesday, 6 May 2020 at 17:46:28 UTC, Q. Schroll wrote:

C++'s decision to make references part of the type has some 
advantages, but D didn't do it because of many disadvantages.


Can you outline or give a link describing the advantages of 
C++'s vs D's choice in this matter?


Whether something is an advantage is subjective at least in some 
sense. So whether you in particular consider something I'll list 
here an advantage is basically your choice.


1. You can have variables ("data members") of reference type in 
structs. (They work like head-const pointers; if D had head-const 
or at least head-const pointers, those would be practically the 
same, only that references cannot be null.)
2. Templates can manipulate ref-ness and so on by type building. 
Notably, I had trouble writing templates that handle non-copyable 
types correctly at ctfe. The reason was that implicit moving 
(moving of temporaries) is done entirely by the compiler, but 
manual moving (std.algorithm.mutation.move) does do stuff (it 
doesn't just trick the compiler into moving casting stuff to 
rvalue references).
3. You can have local variables that are references. While not 
really different from pointers, I think they look less scary than 
pointers.
4. Especially in casts, you can trick the compiler into doing 
things without the fear of generating unnecessary code (in C++, 
std::move and std::forward are mere casts that you could do 
yourself but look awkward).


Potentially, I'm missing something.

Personally, I think D did the right thing making references a 
storage class. You can see very early in learning C++ that 
references are only half-way type constructors: They are not 
fully composable. Normally, you can have arrays and pointers to 
any type, but in C++ you can't have pointers to / arrays of 
references.


Re: How to port C++ std::is_reference to D ?

2020-05-06 Thread Q. Schroll via Digitalmars-d-learn

On Wednesday, 6 May 2020 at 09:07:22 UTC, wjoe wrote:

Hello,

I'm choking on a piece of C++ I have no idea about how to 
translate to D.


std::is_reference


In general, you can't. In D, `ref` is not part of the type, it's 
a "storage class", and as such it is a property that a function 
parameter can have alongside its type. I.e. in C++, it makes 
sense to ask: "Is that parameter's type a reference type?" But in 
D it doesn't; you could ask: "Is the parameter given by 
reference?" ("Does the parameter have the storage class `ref` [or 
`out` to be complete]?")


C++'s decision to make references part of the type has some 
advantages, but D didn't do it because of many disadvantages.


Re: Understand signature of opOpAssign in std/complex.d

2019-11-11 Thread Q. Schroll via Digitalmars-d-learn

On Saturday, 9 November 2019 at 13:26:12 UTC, Adam D. Ruppe wrote:
On Saturday, 9 November 2019 at 12:30:46 UTC, René Heldmaier 
wrote:

The part i don't understand is "is(C R == Complex!R)".
What does that mean?


That's checking the if the template argument C is a case of 
Complex!R, while at the same time declaring a symbol R to hold 
the inner type.


What's the difference of
is(C R == Complex!R)
to
is(C == Complex!R, R)
then?



Bug or Feature: `this` necessary to call function with template this parameter

2019-10-30 Thread Q. Schroll via Digitalmars-d-learn

struct Example
{
private void helper(int i, this X)() { }
void funcTempl(T, this X)(T value)
{
this.helper!0();
//  ^ Why do I need this?
}
}

void main()
{
auto ex = Example();
ex.funcTempl(1);
}

The question is in the comment in the code. Is that intentional 
or a bug?


Array Vararg Template Paremeters

2019-10-30 Thread Q. Schroll via Digitalmars-d-learn
For a function, one can have a vararg parameter at the end like 
this:

int sum(int[] ar ...) { /* code */ }

But for templates, such a declaration is an error. Is there a 
specific reason why?
I know I can do it and ensure all the template parameters are 
values and are convertible to the desired type. However, it's 
easier to just use an array.


For loop with separator

2019-07-04 Thread Q. Schroll via Digitalmars-d-learn

Probably you've come over this problem once in a while, too.
You have a repeating solution, so you use a for(each) loop.
Sometimes, there is an action to be performed between the end of 
one iteration and the beginning of the next, if there is one. The 
prime example is printing the comma when printing a list: There 
is one between any two elements, but neither is one at front or 
behind the last one.


Typical solutions I employed were:
1 Handling the first element separately
2 Condition in the loop, that is false exactly for the first 
iteration.


1 can be done with ranges easily:

if (!range.empty)
{
action(range.front);
range.popFront;
foreach (element; range)
{
betweenAction();
action(element);
}
}

This approach is clearly quite verbose for the problem, but 
there's nothing done unnecessarily.


2 can be done easily, too:

foreach (i, element; range)
{
if (i > 0) betweenAction();
action(element);
}

While 2 is less code, it's prone to be checked every iteration.
Note that 2 is rather D specific in its length. It can be done in 
other languages, but is more verbose.


Is there a cleaner solution that I missed?


How to compile my DMD fork?

2019-06-14 Thread Q. Schroll via Digitalmars-d-learn
Basically the headline. I want to try to implement my DIP. I've 
already forked DMD from GitHub. Now, what would I have to do in 
order to get a D compiler with my changes?


I have Windows on x86-64 and Visual Studio on my machine.


Re: Parameter pack expansion

2019-05-30 Thread Q. Schroll via Digitalmars-d-learn

On Thursday, 30 May 2019 at 20:20:47 UTC, Tomas wrote:
I'm very new to D, coming from C++ I'm missing parameter pack 
expansion and fold expressions.


I also miss the expansion operator and fold expressions.
In D, there is no such thing, and simulating it in a general way 
has so much friction, I just used string mixin to solve these.


I even thought about writing a DIP, but I think, it wouldn't make 
it.
In my static indexing DIP [1], there is a suggestion to add an 
expansion operator, but that would only work on sequences and 
similar things.


If it would be implemented, you could place your parameter pack 
into a Tuple-like structure with an opDispatch that returns such 
a Tuple again, but the contents would be the member components 
"projection" to the member. It's doable[2], but the lack of 
indexing the pack is the main blocker.


If you look closer, the DIP proposes to make "pack..." work by 
replacing it with pack[0], ..., pack[$ - 1] if the indexing and 
length are there to do it.


The DIP doesn't give you parameter or type packs, it gives you 
what you need to implement them; still, fold expressions are 
still not possible. They are rather easy to implement using D's 
template mechanisms and/or string mixin mechanisms. The 
projections to the members in [2] are an example of a fold 
expression.


[1] https://github.com/dlang/DIPs/pull/155
[2] https://run.dlang.io/is/tIxmQS


Alias to template instance wokrs, but non-template does not?

2019-05-14 Thread Q. Schroll via Digitalmars-d-learn

I have the rather strange question: Why does this work?

struct S
{
int value0;

alias opApply = opApplyImpl!(int delegate(ref int)); //1
int opApplyImpl(DG : int delegate(ref int))(scope DG 
callback) //2

{
if (auto result = callback(value0)) return result;
return 0;
}
}

@safe pure nothrow @nogc unittest
{
S xs = S(3);
int sum = 0;
foreach (x; xs) sum += x;
assert(sum == 3);
}

But replacing Lines //1 and //2 with

int opApply(int delegate(ref int) callback)

(replacing the alias to a template instance by equivalent(?) 
non-template code) does not. As far as I know, template 
instantiation should make them exactly the same thing.


The spec does not say anything to this.

Even after replacing //1 by
alias opApply = opApplyImpl!(int delegate(ref int) @system); 
//1

i.e. marking the callback @system explicitly,
the @safe unittest will still compile!

Using
xs.opApply((ref int x) { sum += x; return 0; });
in the unittest directly makes it fail. The compiler claims as 
expected that the template instance is not satisfy the conditions 
for either attribute on the unittest.


But somehow, it does respect attributes. An un-@safe unittest 
like this


static bool b = false;  // some global state to break pure
static foreach (i; 0 .. 4)
{
version(failure)
@safe pure nothrow @nogc unittest
{
static immutable exc = new immutable Exception("");
S xs = S(3);
int* p =  // some pointer to break @safe-ty
foreach (x; xs)
{
static if (i == 0) { p = new int(x); } // 
allocates

static if (i == 1) { ++p; } // un-@safe
static if (i == 2) { b = true; } // impure
static if (i == 3) { throw exc; } // throws 
Exceptions

}
}
}

actually shows that any single attribute can be failed, 
suggesting it is the same for all.


Is there some attribute magic in the compiler's opApply 
rewriting? It should be mentioned.


I've filed a bug report [1] some time ago. I'm posting here, 
because I want to understand what's going on here.


A runnable example is here: https://run.dlang.io/is/KQ0tmL

[1] https://issues.dlang.org/show_bug.cgi?id=19706


Re: Access outer member of struct from inner struct

2019-04-02 Thread Q. Schroll via Digitalmars-d-learn

On Tuesday, 2 April 2019 at 18:52:07 UTC, Jacob Carlborg wrote:

On 2019-04-02 20:44, Q. Schroll wrote:


After removing the calls to writeln, the error I get is:


`this` for `read` needs to be type `Outer` not type `Inner`


You cannot access stuff in Outer because Inner objects are not 
outer objects and don't implicitly own an Outer object. In 
your Inner method `write`, there is no Outer object present at 
all to call the method on.


It works if the struct is nested inside a function [1]. I 
thought it would work nested inside a struct too.


[1] https://dlang.org/spec/struct.html#nested


The reason it works inside a function is that the struct has a 
hidden pointer to the function context. The function's local 
values actually exist when an object of that struct type is being 
instantiated.


The main difference between a struct nested in a function and one 
inside another struct is that the one in a function cannot¹ be 
created outside of that function while constructing the latter is 
possible the way you think it is:


Outer.Inner innerObj = Outer.Inner(parameters);

¹ You can using reflection and stuff like that, but it's still 
broken if it uses the context.


Re: Access outer member of struct from inner struct

2019-04-02 Thread Q. Schroll via Digitalmars-d-learn

On Tuesday, 2 April 2019 at 18:20:09 UTC, Andrey wrote:

Hello,
In this example how can I access the members "read" and "q" of 
struct Outer from Inner struct?

struct Outer
{
ulong q = 1;
Inner inner;

void read(ulong value)
{
q += value;
}

void run()
{
q.writeln;
read(5);
}

struct Inner
{
void write(string text)
{
read(text.length);
writeln(q);
}
}
}

void main()
{
Outer ttt;
ttt.run();
}


During compilation I get:
onlineapp.d(55): Error: this for read needs to be type Outer 
not type Inner

onlineapp.d(56): Error: need this for q of type ulong


After removing the calls to writeln, the error I get is:


`this` for `read` needs to be type `Outer` not type `Inner`


You cannot access stuff in Outer because Inner objects are not 
outer objects and don't implicitly own an Outer object. In your 
Inner method `write`, there is no Outer object present at all to 
call the method on.


How to attach function attributes to delegate type?

2019-02-27 Thread Q. Schroll via Digitalmars-d-learn
For any type constructors like const, I can use ConstOf!T to get 
`T` with const attached. For a delegate/function type DG, e.g. 
int delegate(int), how can I get the @safe version of that type, 
i.e. int delegate(int) @safe?


I tried

alias SafeOf(DG) = DG @safe;

but it didn't compile.

The case is not @safe-specific; it's the same for all function 
attributes.


Re: My template tuple code does not compile

2019-02-27 Thread Q. Schroll via Digitalmars-d-learn
On Wednesday, 27 February 2019 at 03:53:35 UTC, Victor Porton 
wrote:
After following your suggestion to rewrite it with Stride it 
does not work either. I assume the error is somehow related to 
allSatisfy!.


https://github.com/vporton/struct-params-dlang/blob/c1adc86672f46fd6b743903cc270dceef120a8fe/source/struct_params.d

Please help. It is important for both D community and world at 
large.


In

static assert(allSatisfy!(x => isType!x, Types) && ...

you use `allSatisfy` as if it took a lambda function or something 
like that. It does not. It takes a expects a template.


First things first: The spec¹ says that allSatisfy!(F, T) «tests 
whether all given items satisfy a template predicate, i.e. 
evaluates to F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1]).» Here, 
`F` is not a lambda, it's a template.


In your case, you can use `isTypeTuple!Types` from the library² 
to check what you intend to check. For the values, unfortunately 
there is no library function to check that they are all strings. 
A specific solution is to use a (static) template


enum bool isStringValue(alias x) = is(typeof(x) == string);

and feed it to `allSatisfy`:

allSatisfy!(isStringValue, Names)

¹ https://dlang.org/library/std/meta/all_satisfy.html
² https://dlang.org/phobos/std_traits.html#isTypeTuple




Why is my @pure function @system when placed in a struct?

2019-02-27 Thread Q. Schroll via Digitalmars-d-learn
I have a template function `fImpl` I whish to instantiate 
manually using the new name `f`. Reason is simple: `f` should not 
be a template, but overloading it makes it easier that way.

Nothing's more simple in D:

int fImpl(T)(T value) { return cast(int) value; }
alias f = fImpl!int;
alias f = fImpl!long;

It works perfectly used like that.

In my case, `T` isn't just a simple type, it's a delegate type. 
So it's rather like this:


alias BaseDG = int delegate(ref int);
int fImpl(DG : BaseDG)(scope DG callback)
{
// NB: this is @safe iff callback is @safe
int x = 0;
return callback(x);
}

alias myDG = int delegate(ref int) @safe;
alias f = fImpl!myDG;

When I ask the compiler, if `f` is @safe, it tells me: Hurray, it 
is!


pragma(msg, __traits(getFunctionAttributes, f)); // tells me: 
`f` is @safe


For whatever reason, when I put the code in a struct, the @safe 
testing line tells me, it's @system now.


struct S
{
// static: // static or not does not matter

alias BaseDG = int delegate(ref int);
int fImpl(DG : BaseDG)(scope DG callback) { return 0; }

alias myDG = int delegate(ref int) @system;
alias f = fImpl!myDG;

pragma(msg, __traits(getFunctionAttributes, f)); // tells 
me: `f` is @system

}

I have no idea why. It is irrelevant if the function template is 
`static` or even does not call the callback.


Re: My template tuple code does not compile

2019-02-26 Thread Q. Schroll via Digitalmars-d-learn

On Tuesday, 26 February 2019 at 22:56:37 UTC, Victor Porton wrote:

On Tuesday, 26 February 2019 at 22:51:15 UTC, Q. Schroll wrote:
Grouping arguments could be done, but from my experience, it 
does not buy you anything; rather it makes it worse. Better 
just deal with heterogeneous stuff just like 
std.typecons.Tuple does.


After fixing the error you pointed me, it does not work too:

mixin ProviderParams!("S", ((int, "x"), (float, "y")));

Also: Can I nevertheless group arguments?


No, not the way you do. The module std.meta defines AliasSeq as 
follows:


alias AliasSeq(X...) = X;

It is literally equivalent to

template AliasSeq(X...)
{
alias AliasSeq = X; // "eponymous template member"
}

In

mixin ProviderParams!("S", ((int, "x"), (float, "y")));

the parenthesized stuff like (int, "x") is invalid in terms of 
formal grammar. You could use AliasSeq!(int, "x") if you really 
want to display grouping in your source code. Note however that 
this does not do anything. The sequence is being flattened by the 
compiler, i.e.


mixin ProviderParams!("S", AliasSeq!(AliasSeq!(int, "x"), 
AliasSeq!(float, "y")));


is exactly the same as

mixin ProviderParams!("S", int, "x", float, "y");

which I wrote in my answer.

When you don't use a eponymous template member, you can access 
them manually:


template Pack(X...)
{
alias Contents = X; // not "eponymous template member"
}

Using this, you can create what I call packs. For some template 
T, while T!(AliasSeq!(int, bool), AliasSeq!(float, string, long)) 
is the same as writing T!(int, bool), the T!(Pack!(int, bool), 
Pack!(float, string, long)) is different from T!(int, bool, 
float, string, long). In the AliasSeq template, the eponymous 
template member feature of D immediately expands the sequence.


If the template T is defined like this:

template T(Args...)
{ .. }

In the AliasSeq case, Args[0] is int, Args[1] is bool, Args[2] is 
float, ...
In the Pack case, Args[0] is Pack!(int, bool), Args[1] is 
Pack!(float, string, long), and Args[0].Contents[0] is int, 
Args[0].Contents[1] is bool, Args[1].Contents[0] is float ...


I've used Packs once to get the Cartesian product of an AliasSeq 
of Packs. It is a mess. I'd only use Packs when absolutely 
necessary; in your case, it does not seem so.


In your case, you seem to need some initial thing "S" and then 
pairs of things.


template you_name_it(Arg, args...)
if (args.length % 2 == 0) // ensures pairs
{
static foreach (i; args.length / 2)
{
// access the type by args[2*i]
// access the name (or whatever) by args[2*i+1]
}
}

You could get the sequence of types and the sequence of names 
using


alias Types = Stride!(2, args);
alias Names = Stride!(2, args[1 .. $]);


Re: My template tuple code does not compile

2019-02-26 Thread Q. Schroll via Digitalmars-d-learn

On Tuesday, 26 February 2019 at 21:43:31 UTC, Victor Porton wrote:
Compilation of unittest at the bottom of this file fails with 
an error. What is my error?


I cannot tell you, why exactly you get these error messages. I 
can explain you the probable cause of the errors. I have not 
tested anything of what I tell you, as it is very vague.


You have the line

   ProviderParams("S", ((int, "x"), (float, "y")));

Why do you even expect it to compile?
First, ProviderParams is a mixin template, so you'd need to 
instantiate it with the ! operator. Then, the expressions (int, 
"x") and so on do not make sense in D. You could have 
compile-time tuples (using AliasSeq from std.meta) containing 
types and other compile-time known stuff, but it wouldn't help 
directly.

You'd use the mixin template like this:

   mixin ProviderParams!("S", int, "x", float, "y");
   ^-- necessary   ^-- necessary

Grouping arguments could be done, but from my experience, it does 
not buy you anything; rather it makes it worse. Better just deal 
with heterogeneous stuff just like std.typecons.Tuple does.


You should definitely comment your code. Explain what you intend 
to do. It helps people helping you.


Re: Syntax for Pointer to Class

2019-01-25 Thread Q. Schroll via Digitalmars-d-learn

On Friday, 25 January 2019 at 20:31:29 UTC, H. S. Teoh wrote:
On Fri, Jan 25, 2019 at 08:12:33PM +, Q. Schroll via 
Digitalmars-d-learn wrote:

Say I have a class C and I want a pointer to a C handle.


Note that taking the address of `C` will actually give you a 
pointer to the reference, not the pointer to the class instance 
itself.


I know. This is precisely the thing I asked for: A pointer to a 
handle. I called it handle for exactly this reason.


For that to be valid, you'll need to store your class reference 
somewhere first, since it's invalid to take the address of an 
rvalue


Yes. ` C(...)` looked to wrong for me to even consider trying.


C c = new C(...);
C* ptrToRef = 


So the answer is no. At least not that simple.

Be warned that the pointer will become invalid when the 
reference `c` goes out of scope, even if the object itself is 
still live (via another reference), because the pointer is 
pointing to the class reference rather than the actual object.


That's kind of obvious if you get remembered, but thanks. I 
wasn't considering this as I wanted the handle to live on the 
heap anyway --- the same way for a struct `S`, the pointer 
pointed to by `S** ptr = new S*(new S(...));` lies on the heap.


I'll use

C* ptr = &[ new C(...) ][0];

for now. It looks ugly, but it does the job.


Syntax for Pointer to Class

2019-01-25 Thread Q. Schroll via Digitalmars-d-learn

Say I have a class C and I want a pointer to a C handle.

I tried the following pieces of syntax:

  C* obj = new C(); // gives me a C
  C* obj = new C*(); // gives me a C**
  C* obj = C*(); // refuses to compile

Is it even possible? This sounds so newbie...
I know it's fairly simple with structs: S() gives me a struct 
instance, new S() gives me a ptr to a struct instance.


Re: Am I misusing with?

2019-01-19 Thread Q. Schroll via Digitalmars-d-learn

On Saturday, 19 January 2019 at 20:38:00 UTC, faissaloo wrote:

On Saturday, 19 January 2019 at 20:07:34 UTC, Rubn wrote:

On Saturday, 19 January 2019 at 17:49:31 UTC, faissaloo wrote:

[...]


If you look at the implementation, "lines" is a struct.

https://github.com/dlang/phobos/blob/v2.084.0/std/stdio.d#L4330

[...]


Ah that makes some sense, thanks for the explanation.


If you import symbols explicitly, you'd have known.

Probably in your code:

import std.file;

What should be there:

import std.file : File, lines;

If lines is a member of the File struct, the import fails. If 
lines is not a member of File, not importing it fails. You get 
more detailed information.

Using import bind lists [1] usually is a good idea.

[1] https://dlang.org/spec/module.html#import-declaration


Re: Can you move a disabled this(this) struct in to a container type if it's an rvalue?

2018-12-15 Thread Q. Schroll via Digitalmars-d-learn
On Thursday, 13 December 2018 at 23:33:39 UTC, Stanislav Blinov 
wrote:

On Thursday, 13 December 2018 at 13:17:05 UTC, aliak wrote:

Ah. Is there any case where you would not want to do that when 
you have a T value as parameter?


Hypothetically, yes, e.g. an object that contains references to 
itself. However, D operates on the assumption that you don't 
have such objects.


The spec actually forbids you creating self referencing structs. 
DIP 1014 tackles that. For the spec, see 
https://dlang.org/spec/garbage.html#pointers_and_gc






Re: Move and CTFE

2018-05-30 Thread Q. Schroll via Digitalmars-d-learn

On Wednesday, 30 May 2018 at 21:02:07 UTC, Jonathan M Davis wrote:
On Wednesday, May 30, 2018 20:42:38 Q. Schroll via 
Digitalmars-d-learn wrote:
It seems one cannot std.algorithm.mutation.move objects 
explicitly. Say I have a non-copyable type

[...]
It fails because move() cannot be executed at compile time. The
reason
 "memcpy cannot be interpreted at compile time, because it 
has

no available source code"
sounds very suspicious.


Why is it suspicious? memcpy is a C function, and you can't 
call C functions during CTFE precisely because the compiler 
doesn't have their source code. You can't call D functions 
either if the compiler doesn't have their source (e.g. if 
you're using a .di file to hide the implementation).


I definitely do understand the error message and it makes sense 
that it fails the way it's implemented. However, it makes no 
sense that moving as a concept can fail at CTFE. That's what I 
find suspicious. [Maybe 'suspicious' isn't the right term; I 
couldn't express it better.] You can move rvalues at CTFE which 
proves that the compiler can do it.



Shouldn't it be possible to move at CTFE,
too, or does it mean, non-copyable types are practically 
unusable

for CTFE?


You can't do much in the way of pointer or memory manipulation 
during CTFE (e.g. no pointer arithmetic or reinterpret casts). 
So, I don't see how a move could be done during CTFE. Even if 
the source for memcpy were available during CTFE, I suspect 
that it wouldn't be allowed due to the lower level stuff that 
it does.


That's the explanation why probably all currently possible 
library alternatives to memcpy would fail. I suspected that when 
encountering the error, but still wonder why memcpy or other 
low-level stuff is even necessary to accomplish something the 
compiler is perfectly able to do.


From what I see, the reason for the hack is lack of 
expressiveness: We don't have rvalue-refs in D (which I find 
good) so, currently, there is no cast-solution as in C++. So for 
a proper move() that works at CTFE, we'd need some specific tool.


I have no idea of the details on how the compiler handles 
lvalues. Would it make sense to add a compiler trait, 
specifically to solve moving? Like __traits(move, 
lvalue_expression) [name up for discussion] that is identical to 
lvalue_expression with the exception that the (lvalue/rvalue) 
flag (or whatever it is) is set to "rvalue". Basically, it's the 
C++ solution: After the "cast", the compiler will proceed and 
pretend it is an rvalue and therefore initiate moving.


Do you think adding a trait to make move() and swap() work at 
CTFE is worth it?


A quick search showed me the class "Expression" has "virtual bool 
isLvalue();" so it might be easy as wrapping and hooking that 
virtual method. To me, [1] highly suggests that it works.


[1] 
https://github.com/dlang/dmd/blob/master/src/dmd/expression.d#L1219




Move and CTFE

2018-05-30 Thread Q. Schroll via Digitalmars-d-learn
It seems one cannot std.algorithm.mutation.move objects 
explicitly. Say I have a non-copyable type


struct NoCopy
{
int payload; // some payload
pure nothrow @nogc @safe @disable:
this(this); // make it non copyable
}

that is being used in a compile-time function evaluation where 
values are being moved.


int f() pure nothrow @nogc @safe
{
import std.algorithm.mutation : move;
NoCopy nc = NoCopy(1), nc2 = NoCopy(3);
nc = move(nc2);
return 0;
}

static assert(f() == 0); // trigger CTFE

It fails because move() cannot be executed at compile time. The 
reason
"memcpy cannot be interpreted at compile time, because it has 
no available source code"
sounds very suspicious. Shouldn't it be possible to move at CTFE, 
too, or does it mean, non-copyable types are practically unusable 
for CTFE?


Re: What's the purpose of the 'in' keyword ?

2018-05-30 Thread Q. Schroll via Digitalmars-d-learn

On Sunday, 27 May 2018 at 16:00:15 UTC, Jonathan M Davis wrote:

[...]
Honestly, I'd suggest that folks never use in at this point.
There's zero benefit to it.
[...]


Exactly. If you intend const, just write const. If you intend 
const scope, write const scope.




Re: Why The D Style constants are written in camelCase?

2018-05-13 Thread Q. Schroll via Digitalmars-d-learn

On Wednesday, 9 May 2018 at 09:38:14 UTC, BoQsc wrote:
The D Style suggest to camelCase constants, while Java naming 
conventions always promoted uppercase letter.


Is there an explanation why D Style chose to use camelCase 
instead of all UPPERCASE for constants, was there any technical 
problem that would appear while writing in all UPPERCASE?




Java language references:
https://en.wikipedia.org/wiki/Naming_convention_(programming)#Java
https://www.javatpoint.com/java-naming-conventions
http://www.oracle.com/technetwork/java/codeconventions-135099.html
https://medium.com/modernnerd-code/java-for-humans-naming-conventions-6353a1cd21a1



D lang reference:
https://dlang.org/dstyle.html#naming_constants


It is really helpful to write generic code. E.g. you use 
`myRange.empty` and you do not care what `empty` actually is. The 
range could be infinite and define `enum empty = false;` If you 
use an uppercase identifier like `EMPTY`, generic code breaks; if 
you don't but do otherwise, where is the boundary? The only 
solution is, you don't spell it different if something is a 
compile-time constant or not.
It is even possible that some name can refer to a type, which is 
usually spelled with the first letter uppercase, or a value.
On [1] it reads: `hook` is a member variable [of type `Hook`] if 
it has state, or an alias for `Hook` [the type itself] otherwise.
So, generally, anything is spelled camelCase except declared 
types as classes, interfaces, structs, unions, and aliases for 
things definitely known to be types.


[1] 
https://dlang.org/phobos/std_experimental_checkedint.html#.Checked.hook


Re: Purity of delegate-style toString

2018-05-06 Thread Q. Schroll via Digitalmars-d-learn

On Tuesday, 1 May 2018 at 12:03:15 UTC, ag0aep6g wrote:

On 05/01/2018 01:44 PM, Per Nordlöw wrote:
In which cases (if any) is it possible to make a 
delegate-style implementation of toString such as


     void toString(scope void delegate(const(char)[]) sink) 
const @trusted pure

     {
     // sink("...");
     // sink.formattedWrite!"..."(...);
     }

pure?


You have to mark `sink` as pure, too:

void toString(scope void delegate (const(char)[]) pure sink)
const @trusted pure

Then the toString method itself works, but it may not be 
callable by other code that wants to use an impure sink.


For example, `format` works, but `writeln` doesn't:


struct S
{
void toString(scope void delegate(const(char)[]) pure sink)
const @trusted pure
{
import std.format: formattedWrite;
sink("...");
sink.formattedWrite!"%s"(" ...");
}
}
void main()
{
import std.format: format;
import std.stdio: writeln;
writeln(format("%s", S())); /* Ok. Prints "... ...". */
writeln(S()); /* Nope. writeln would like to use an impure 
sink. */

}


By the way, you shouldn't mark toString as @trusted when `sink` 
is @system.


I had similar issue for opApply.

The generalized problem is, the attributes (pure, nothrow, @safe, 
@nogc) are too strong on functionals (i.e. functions taking 
function/delegate arguments). We could (and IMO should) weaken 
the attributes to mean: the same as always, *assuming all 
function/delegate arguments have it*.


Concrete example, say your `toString(scope void 
delegate(const(char)[]))` is conceptually pure, i.e. if `sink` is 
a pure function (by static typing), `toString(sink)` acts pure, 
and for impure `sink`, `toString(sink)` possibly impure. So 
purity of the functional `toString` depends on the purity of its 
arguments; that is very natural as most functionals call their 
parameters.


The current state makes attributes virtually useless for 
functionals. Often, toString can be templetized without drawback 
(except virtual functions), but opApply cannot. opApply must not 
be a template to enable type deduction for the variable.[1]


Making attributes act structurally has almost no consequences in 
terms of breakage; just more functions can be 
pure/nothrow/@nogc/@safe. It would make functionals 
impure/unsafe/..
that do not call their argument. The question is, in which 
contexts are they used and is it an issue -- is it a greater 
issue than this.


Complete example what the change would do:
Say you have

  void toString(scope void delegate(const(char)[]) sink) pure { 
sink("Example"); }


toString is a pure functional, so calling it is pure iff the 
argument itself is. The compiler statically knows if the argument 
is pure and can infer the purity of the expression.


[1] 
https://dlang.org/spec/statement.html#foreach_over_struct_and_classes
(We could define very general special cases where type deduction 
can be archived, e.g. opApply(DG : int delegate(Args))(DG).)


Overload Resulution Template with 2 Functions vs. 2 Templates difference

2018-05-06 Thread Q. Schroll via Digitalmars-d-learn

Why is there a difference between

struct S
{
  template func(T)
  {
enum impl = "whatever string";
auto func(T arg)   { mixin(impl); } // eponymous template
auto func(T arg) const { mixin(impl); } // eponymous template
  }
}

and

struct R
{
  private enum impl = "whatever string";
  auto func(T)(T arg)   { mixin(impl); }
  auto func(T)(T arg) const { mixin(impl); }
}

And what is the difference exactly? I know that
  auto func(T)(T arg) { mixin(impl); }
is strictly equivalent to
  template func(T) { auto func(T)(T arg) { mixin(impl); } }
so the difference is just 2 templates 1 function each vs. 1 
template 2 functions.


I don't have a simple example; here is no difference observable. 
The issue is with std.typecons.Tuple.opCmp; there are two 
templates and I tried making it one, as the implementation is 
identical. Unfortunately, one cannot use `inout` for more or less 
obcious reasons.
An attempt to put them into one template (as for struct S) does 
not work either, but I don't understand why. Solution like struct 
R works.


Is there a complete reference for how overload resolution works 
in D, including implicit template instantiation?


simple DIP1000 test fails?

2017-11-02 Thread Q. Schroll via Digitalmars-d-learn

I've tried to get into the changes by DIP1000 and discovered this:

struct S { ref S id() return { return this; } }
void main() { S* p = ().id(); }

Should it really compile? (rdmd -dip1000 .\test_return_ref.d)


Re: Why 2 ^^ 1 ^^ 2 = 2?

2017-11-01 Thread Q. Schroll via Digitalmars-d-learn

On Saturday, 28 October 2017 at 00:14:15 UTC, Ivan Kazmenko wrote:
For an argument, the TEX command "^" accepts either a single 
character or a bracket-enclosed string of arbitrary length.  So 
$3^3^3$ indeed transforms to ${3^3}^3$, but not for some deeper 
reason this time.


On my TeX compiler, $3^3^3$ makes it give a warning/error.



if (auto x = cast(C) x)

2017-08-09 Thread Q. Schroll via Digitalmars-d-learn
For a class/interface type `A` and a class `C` inheriting from 
`A` one can do


  A a = getA();
  if (auto c = cast(C) a)
  { .. use c .. }

to get a `C` view on `a` if it happens to be a `C`-instance.

Sometimes one cannot find a good new name for `c` while there is 
no advantage of accessing `a` when `c` is available. D does not 
allow to shadow `a` in the if-auto declaration for good reasons. 
How about relaxing the rule for cases like these, where the rhs 
is the lhs with a cast to derived?


  if (auto a = cast(C) a)
  { .. use a typed as C .. }

One can think of `a` being *statically* retyped to `C` as this is 
a (strictly) better type information. Internally, it would be a 
shadowing, but it does not matter as the disadvantages don't 
apply (if I didn't miss something).


Re: BigInt foreach loop

2017-08-09 Thread Q. Schroll via Digitalmars-d-learn

On Friday, 4 August 2017 at 16:40:08 UTC, Stefan Koch wrote:

[..]

foreach(x;A .. B)
it's lowerd to
auto limit = B;
auto key = A;
for(auto x = key;key < limit;++key)
{
 // use x
}


That's enough to know that the foreach loop does not reuse the 
space for the iteration variable. That was what I cared about.


BigInt foreach loop

2017-08-04 Thread Q. Schroll via Digitalmars-d-learn

One can do
  BigInt n = returnsBigInt();
  foreach (i; BigInt(0) .. n)
  { .. }
How is this implemented? The code for BigInt is very large and I 
didn't find it.

And is it more efficient than
  for (BigInt i = 0; i < n; ++i)
  { .. }
as incrementing is a costly operation?


Re: Search for, o/w create element for AA

2017-06-19 Thread Q. Schroll via Digitalmars-d-learn

On Monday, 19 June 2017 at 16:54:46 UTC, Ali Çehreli wrote:

On 06/19/2017 08:19 AM, Q. Schroll wrote:

Can't I tell the AA to set a value for a given key if it 
doesn't already

have one
 (1) with only one lookup, and
 (2) in a safe way?


aa.get(key, defaultValue)

  https://dlang.org/spec/hash-map.html#properties

Ali


aa.get returns the defaultValue if the key is not in the AA, but 
does not add the key-value pair (x, defaultValue) to the AA. I'd 
find it rather surprising if it did.


Search for, o/w create element for AA

2017-06-19 Thread Q. Schroll via Digitalmars-d-learn

Trying to implement some random function I encountered this:

uint randFunc(uint x)
{
static uint[uint] vals;
if (auto r = x in vals) return *r;
return vals[x] = uniform!uint();
}

I have to lookup x twice and it seems that there is no way around 
it. Can't I tell the AA to set a value for a given key if it 
doesn't already have one

 (1) with only one lookup, and
 (2) in a safe way?
For the semantics, that should behave like this:

V set(K, V)(ref const(V)[const(K)] aa, auto ref const(K) key, 
lazy const(V) value)

{
if (auto valPtr = key in aa) return *valPtr;
// cast away const as initialization is okay:
return (cast() aa[key]) = value();
}

The function is dual to AA's get.

It would make it possible for an AA with const value type to have 
values added which is perfectly fine for arrays. All I have seen 
so far, one cannot safely add values to them as initialization 
and assignment cannot be distinguished.


Re: Function Template Overloading

2017-03-14 Thread Q. Schroll via Digitalmars-d-learn

On Wednesday, 15 March 2017 at 02:33:36 UTC, ketmar wrote:

Q. Schroll wrote:


void test(T)(T* arg);
void test(T)(ref T arg);

Let p be any pointer. Why is test(p) not an ambiguity error? 
Why is the second overload chosen?


'cause `ref T` is more generic than `T*`. think of it as 
"greedy matching": compiler first tries to match `int*`, and if 
that failed, it tries `int`, for example. and `int*` matches 
the second template, so compiler choosing it.


Wouldn't it be better vice versa, the more specific pattern to be 
prioritized? And as it actually *can* match both, is it a 
compiler-bug not to be an ambiguity error?


Function Template Overloading

2017-03-14 Thread Q. Schroll via Digitalmars-d-learn

void test(T)(T* arg);
void test(T)(ref T arg);

Let p be any pointer. Why is test(p) not an ambiguity error? Why 
is the second overload chosen?
Making the first one take auto ref T* lets the compiler choose 
the first.
Making the second one non-ref lets the compiler give me an 
ambiguity error.


Template Functions are not mentioned in the spec, at least not on 
https://dlang.org/spec/function.html#function-overloading, but it 
suggests that ref should not make the decision if it can be bound 
to.


Re: How to compile against GitHub fork of Phobos?

2017-03-06 Thread Q. Schroll via Digitalmars-d-learn

On Tuesday, 7 March 2017 at 02:30:21 UTC, ketmar wrote:

Q. Schroll wrote:


On Tuesday, 7 March 2017 at 01:45:48 UTC, Adam D. Ruppe wrote:

You pass your modified file to the compiler:

dmd yourfile.d format.d

The format.d there can be a copy of the one from phobos (or a 
fork or whatever) and since you passed it explicitly on the 
command line, it takes precedence over the one in the library.


You still import it as std.format. You can do that with as 
many modules as you like.


I just tried it out.

dmd myfile.d phobos/std/format.d

worked fine, but interestingly,

rdmd myfile.d phobos/std/format.d

did not. The latter definitely takes format from the library. 
I have no idea why.


rdmd doesn't work like dmd. here, it just passing 
"phobos/std/format.d" as command line argument to "myfile.d".


You're right. I should've known that. By bad ...

Thanks for your replies. They were very helpful.


Re: How to compile against GitHub fork of Phobos?

2017-03-06 Thread Q. Schroll via Digitalmars-d-learn

On Tuesday, 7 March 2017 at 01:45:48 UTC, Adam D. Ruppe wrote:

You pass your modified file to the compiler:

dmd yourfile.d format.d

The format.d there can be a copy of the one from phobos (or a 
fork or whatever) and since you passed it explicitly on the 
command line, it takes precedence over the one in the library.


You still import it as std.format. You can do that with as many 
modules as you like.


I just tried it out.

   dmd myfile.d phobos/std/format.d

worked fine, but interestingly,

   rdmd myfile.d phobos/std/format.d

did not. The latter definitely takes format from the library. I 
have no idea why.


How to compile against GitHub fork of Phobos?

2017-03-06 Thread Q. Schroll via Digitalmars-d-learn
I have a fork of the standard-library in the folder "phobos". In 
version 2.072.1 of the compiler, I could use code like


void main()
{
import phobos.std.format;
/* code for checking my changes to format */
}

compiled with

  $ dmd -I"phobos" test_format.d

in the parent folder of phobos. It worked fine.

I've updated the compiler today and get an error message:

module std.typecons from file phobos\std\typecons.d must be 
imported with 'import std.typecons;'


But if I do so, it imports the one from the standard library 
attached to the compiler. Is it a regression? Should the old 
version have rejected my code? I don't see any possibility to 
test specific changes in modules of my fork.


I've just read 
https://wiki.dlang.org/Starting_as_a_Contributor#Building_D, but 
it didn't help me out.


Why don't Function Lambdas Cast to Delegate?

2016-11-21 Thread Q. Schroll via Digitalmars-d-learn
Why don't lambdas cast to a delegate if they are of type R 
function(Args)? I don't see any reason to that; a lambda should 
be a delegate type by default, and a function only as a special 
guarantee/optimization. It just makes them cumbersome to use with 
toDelegate.
Probably there is a good reason why R function(Args) does not 
implicitly cast to R delegate(Args); I can imagine something 
internally (memory layout etc.) causes that. I'd just like to 
know.


Using opApply and Attributes

2016-11-20 Thread Q. Schroll via Digitalmars-d-learn
When using functions with delegate (or function ptr) parameters 
which should comply with some attributes, I cannot call the 
delegate in the function what makes it pretty useless (I haven't 
done research, but I claim that generally most functions taking 
delegate parameters call them).


  void f1(void delegate(int) dg) // cannot be pure ...
  {
dg(1); // ... due to this call.
  }

  void main() pure
  {
f(x => 2*x); // Error, f is impure.
  }

One has to overload the function like
  auto f(delegate(Arg arg) @attrib dg) @attrib;
  auto f(delegate(Arg arg) dg);
for each combination of attributes available (today 4, worst case 
is 16 overloads), could be more in the future.


Even worse (due to bug 15859, see [1]) overload resolution on 
opApply does not work properly. Making opApply a template is a 
real solution for various reasons (virtual functions, no type 
inference on the delegate, etc.). For opApply, using the range 
interface (empty, front, popFront) is not a real solutions either 
because opApply can be truly recursive. Those can then only have 
a range interface through generators via fibers which have an 
overhead (and make them non-@nogc).


How can I have relative-@attrib functions without unnecessary 
manual overloading?
(relative: if all called parameter delegates have it, then the 
function has it)


Generally, are relative attributes worth an enhancement?

[1] https://issues.dlang.org/show_bug.cgi?id=15859


std.algorithm.iteration.each requires opApply to have ref elements?

2016-09-15 Thread Q. Schroll via Digitalmars-d-learn

Why does it do that?
And seemingly it does not require it for opApply with more than 
two arguments.


Re: inferred vs. annotated attributes

2016-09-10 Thread Q. Schroll via Digitalmars-d-learn
On Saturday, 10 September 2016 at 09:38:15 UTC, Lodovico Giaretta 
wrote:
On Saturday, 10 September 2016 at 08:23:35 UTC, Q. Schroll 
wrote:
Is there a difference between inferred and annotated 
attributes?

Example:

struct X(T)
{
this(S)(in S[] arr) // inferred pure
{ }
}

void main() pure
{
X!uint mut = [ 1, 2 ]; // proves inference (cf. main 
is pure)

// immutable X!uint imm1 = [ 1, 2 ];
// auto imm2 = immutable X!uint([1, 2]);
}

The commented lines yield error messages claiming the 
constructor cannot deduce function from argument types 
!()(int[]) immutable, however it can, if "pure" is explicitly 
annotated.


Is this a bug or did I get something wrong about inference / 
unique expressions?


A method (included ctors) that is not annotated const, nor 
immutable, nor inout, is implicitly mutable. This implies that 
your ctor is mutable, and as such it cannot create immutable 
instances.


IIRC, a pure ctor can construct any objects (including immutable 
and shared).


If you add another ctor marked immutable, everything works. An 
alternative is to mark the ctor as inout.


Technically I know. The minimal example only explains the 
problem/bug. My real constructor does do things where I don't 
want inout attributes if I can avoid.


I tested this solution and it works, but I'm not sure if it is 
by design.


Sure. It did for me, too.

The question is: Why does annotating an inferred attribute make a 
difference? (Or it doesn't and I don't see it all the time.)


inferred vs. annotated attributes

2016-09-10 Thread Q. Schroll via Digitalmars-d-learn

Is there a difference between inferred and annotated attributes?
Example:

struct X(T)
{
this(S)(in S[] arr) // inferred pure
{ }
}

void main() pure
{
X!uint mut = [ 1, 2 ]; // proves inference (cf. main is 
pure)

// immutable X!uint imm1 = [ 1, 2 ];
// auto imm2 = immutable X!uint([1, 2]);
}

The commented lines yield error messages claiming the constructor 
cannot deduce function from argument types !()(int[]) immutable, 
however it can, if "pure" is explicitly annotated.


Is this a bug or did I get something wrong about inference / 
unique expressions?


Re: opAssign return type

2016-09-02 Thread Q. Schroll via Digitalmars-d-learn
On Friday, 2 September 2016 at 17:33:22 UTC, Steven Schveighoffer 
wrote:

On 9/2/16 1:18 PM, Q. Schroll wrote:
When overloading assignment, I've been taught in my C++ course 
to return
a reference to the lvalue being assigned to. This is easily 
possible in
D, but in Phobos it is used rarely and in Ali Çehreli's Book 
it is

neither taught to do so.


Sure, you can do this.

Is there any reason to it? To me it seems very obvious to do 
it like in

C++.


I can imagine a reason is to avoid issues with lifetime. It's 
dangerous to return this as a reference in most cases, because 
this is implicitly passed by reference even for rvalues.


However, for opAssign, you generally are sure you don't have an 
rvalue.


Interestingly the compiler does not allow rvalue = expr but it 
does however allow rvalue.opAssign(expr).


In any case, there's nothing wrong with it technically, it 
should work.


-Steve


There is no possibility to enforce some method is only available 
for lvalue this?




opAssign return type

2016-09-02 Thread Q. Schroll via Digitalmars-d-learn
When overloading assignment, I've been taught in my C++ course to 
return a reference to the lvalue being assigned to. This is 
easily possible in D, but in Phobos it is used rarely and in Ali 
Çehreli's Book it is neither taught to do so.


Is there any reason to it? To me it seems very obvious to do it 
like in C++.


The question came up in the discussion of a PR:
https://github.com/dlang/dlang.org/pull/1466


Re: Use dup on Containers with const Elements

2016-07-30 Thread Q. Schroll via Digitalmars-d-learn
On Friday, 29 July 2016 at 19:24:59 UTC, Steven Schveighoffer 
wrote:

On 7/29/16 3:00 PM, Q. Schroll wrote:
Cases to consider: Arrays and AAs with const(T) Elements, 
where T is a

value or a reference type respectively.


[snip]

Questions:
(1) Why do I have to specify the type here? Why does inference 
fail?

(2) Why not just S[S]?
The copy of a const S is a S so why is the copy of a (const S, 
const

S)-pair not just (S, S)?



array.dup has the meaning to copy the original but make the 
elements mutable. At least, that's what it was when it was 
handled by the compiler/runtime.


I do understand the reasons why I can't simply copy const 
reference type objects to mutable. It just makes sense as the 
referred object is still const.
I thought of dup being there for convenience and performance 
reasons. The spec says about dup: "Create a dynamic array of the 
same size and copy the contents of the array into it."
It has not been clear to me it intends to make the elements 
mutable. For my intention, I thought of dup making a shallow 
copy--which is a deep copy on value types so it can drop the 
const then.


So the reason for 1 is that you can't convert const(C) to just 
C without a cast, so you must specify the type.


The implementation is made so that I have to. This one is obvious 
then.


I'm not certain about AA, as I don't remember how dup was 
defined on them.


-Steve


I just wonder if it is a bug. If it is true, then it's a 
misfeature or badly specified function.


Use dup on Containers with const Elements

2016-07-29 Thread Q. Schroll via Digitalmars-d-learn
Cases to consider: Arrays and AAs with const(T) Elements, where T 
is a value or a reference type respectively.


class C { }
struct S { }

const(S)[]  varr;
const(C)[]  carr;
const(S)[S] vaav;
const(C)[S] caav;
const(S)[C] vaac;
const(C)[C] caac;

pragma(msg, typeof(varr.dup));
pragma(msg, typeof(carr.dup!(const C))); // (1)
pragma(msg, typeof(vaav.dup));
pragma(msg, typeof(caav.dup));
pragma(msg, typeof(vaac.dup));
pragma(msg, typeof(caac.dup));

yields

S[] // ok
const(C)[]  // ok
const(S)[S] // (2)
const(C)[S] // ok
const(S)[C] // ok
const(C)[C] // ok

Questions:
(1) Why do I have to specify the type here? Why does inference 
fail?

(2) Why not just S[S]?
The copy of a const S is a S so why is the copy of a (const S, 
const S)-pair not just (S, S)?




Re: Associative array of const items

2016-06-30 Thread Q. Schroll via Digitalmars-d-learn

On Thursday, 30 June 2016 at 17:08:45 UTC, Jonathan Marler wrote:
Is there a way to have an associative array of const values? I 
thought it would have been:


const(T)[K] map;
map[x] = y;

but the second line gives Error: cannot modify const 
expression.  I would think that the const(T)[K] would behave 
similarly to const(T)[], where you can modify the array, just 
not the individual elements, but associative arrays don't seem 
to have the same semantics.  Is there a way to achieve these 
semantics with an associative array?


It is possible to initialize the array with a AA literal as
const(int)[string] aa = [ "1": 1, "2": 2 ];
but AAs don't have opIndexAssign etc.
The reasonable things you do to const(T)[] is shorten it or 
reassign it completely.
For an AA, this is removing elements or adding new ones. While 
the first is without problems, the problem is how to determine if 
aa["1"] = 1 is a (legal) initialization or (illegal) reassignment 
of a const(T). Unfortunately, there is no function to add 
key-value-pairs that throws an Error if the key is already there 
or else reinitializes the value.


Formatted Output: Exact number of Decimal Places

2016-05-16 Thread Q. Schroll via Digitalmars-d-learn
Lets say I want to print a table with floats. How can it be 
formatted like that:

|  2.4   |
| 12.2   |
|  8.131 |
| 17.44  |
Also acceptable is
|  2.400 |
| 12.200 |
|  8.131 |
| 17.440 |
but not
| 02.4   |
| 12.2   |
| 08.131 |
| 17.44  |
or any other solutions with leading zeros.


Re: pure opApply

2016-03-31 Thread Q. Schroll via Digitalmars-d-learn
On Thursday, 31 March 2016 at 13:51:00 UTC, Steven Schveighoffer 
wrote:
I think it's a bug. foreach and opApply are specially coded in 
the compiler I think, so there's bound to be inconsistencies 
between them and normal overload rules.


-Steve


I have never filed a bug report. Should this be reported? How and 
where to do?


Re: foreach UFCS

2016-03-31 Thread Q. Schroll via Digitalmars-d-learn

On Thursday, 31 March 2016 at 13:39:25 UTC, ixid wrote:

What is going on with UFCS and foreach?

foreach(i;0..5).writeln;


This is not UFCS; it is calling writeln on module scope. See 
http://dlang.org/spec/module.html#module_scope_operators


Your code is semantically identical with

foreach (i; 0 .. 5)
{
.writeln; // module scope operator!
}

Furthermre because there is no local variable writeln that could 
be confused with the imported function, the code is identical with


foreach (i; 0 .. 5)
{
writeln;
}


This prints five line breaks.

foreach(i;0..5).i.writeln;

This will not compile.


It does not compile because i is not an identifier at module 
scope. i is a local variable and a hypothetical i at module scope 
(accessible via .i) is not declared, therefore this is an error.



foreach(i;0..5).writeln(i);

This writes out 1 to 4 on separate lines. Is this supposed to 
work? I thought a.b would be rewritten to b(a) with UFCS but 
writeln(foreach(i;0..5)) is nonsensical and does not compile 
and should be the same as foreach(i;0..5).writeln;


It does rewrite. But only if there is an expression beforehand 
the dot. Here it just isn't. The "foreach (i; 0 .. 5)" is not a 
complete expression.


pure opApply

2016-03-31 Thread Q. Schroll via Digitalmars-d-learn

Simple as that, shouldn't this work?

struct X
{
int opApply(int delegate(string) dg)
{
return dg("impure");
}

int opApply(int delegate(string) pure dg) pure
{
return dg("pure");
}
}

void main()
{
X x;
string result;

x.opApply(
(string s)
{
result = s;
return 0;
}
);
writeln(result); // does compile and prints "pure".

x.opApply(
(string s)
{
result = s;
write("");
return 0;
}
);
writeln(result); // does compile and prints "impure".

/+ (1)
foreach (string s; x)
{
result = s;
}
writeln(result); // does not compile: x.opApply matches more 
than one declaration

+/
/+ (2)
foreach (string s; x)
{
result = s;
write("");
}
writeln(result); // does not compile: x.opApply matches more 
than one declaration

+/
}

Can someone explain me, why the compiler cannot resolve the right 
opApply? From what I know, it generates a delegate with inferred 
pure attribute and looks for the best match of opApply. Why does 
the manual rewrite work? If I've done the rewrite improperly, 
please tell me.


Arithmetic conversion -- warnings missing?

2015-09-03 Thread Q. Schroll via Digitalmars-d-learn

import std.stdio;

void main()
{
short  ss = -1;
ushort us =  0;
intsi = -1;
uint   ui =  0;
if (ss < us)
writeln("a");
else
writeln("b");

if (si < ui)
writeln("A");
else
writeln("B");
}

prints "aB" due to integral promotion and arithmetic conversion 
rules. I know it's this kind of thing: If it compiles and looks 
like c, it behaves the same.

But why does it compile and why does it so without any warning?
Is there any rationale to make this even work?