Re: What's the point of static arrays ?

2020-07-10 Thread Stanislav Blinov via Digitalmars-d-learn

On Friday, 10 July 2020 at 10:13:23 UTC, wjoe wrote:

So many awesome answers, thank you very much everyone!

Less overhead,
Using/needing it to interface with something else, and
Efficiency are very good points.

However stack memory needs to be allocated at program start. I 
don't see a huge benefit in allocation speed vs. heap 
pre-allocation, or is there?


Stack is allocated by the OS for the process when it's started. 
Reserving space for stack variables, including arrays, is 
effectively free, since the compiler assigns offsets statically 
at compile time.


I mean 1 allocation vs 2 isn't going to noticeably improve 
overall performance.


A GC allocation is way more complex than a mere bump-the-pointer. 
If your program is trivial enough you may actually find that one 
extra GC allocation is significant in its runtime. Of course, if 
you only ever allocate once and your program runs for ages, you 
won't really notice that allocation.



a[]

What happens here exactly ?


This:

int[10] a;
int[] slice = a[];
assert(slice.ptr == [0]);
assert(slice.length == 10);
assert(a.sizeof == 10 * int.sizeof);// 40
assert(slice.sizeof == (int[]).sizeof); // 16 on 64 bit

I read the chapters in Ali's book (thank you very much for such 
a great book, Ali) on arrays and slicing prior to asking this 
question and I came to the following conclusion:


Because a static array is pre-allocated on the stack,
doesn't have a pointer/length pair,
is addressed via the stack pointer, and
due to the fact that a slice is a pointer/length pair
  and because a slice is technically the meta data of a dynamic 
array, a view into (part) of a dynamic array,


No. A slice is just a pointer/length pair - a contiguous view 
into *some* memory, regardless of where that memory came from:


void takeASlice(scope void[] data) // can take any slice since 
any slice converts to void[]

{
import std.stdio;
writefln("%x %d", data.ptr, data.length);
}

int[10] a;
takeASlice(a); // a[]
takeASlice(a[1 .. $-1]); // a[1 .. 9]

struct S
{
float x, y, z;
float dx, dy, dz;
}

S s;
takeASlice(()[0 .. 1]); // Slicing a pointer, not @safe but can 
be done.

takeASlice(new int[10]); // Array, GC allocation
takeASlice([1, 2, 3, 4]); // Array literal, may or may not be 
GC-allocated


`takeASlice` has no knowledge of where the memory came from.

Dynamic arrays only ever come into the picture if you try to 
manipulate the slice itself: resize it, append to it, etc.


that it's not possible to slice a static array because the 
slice would technically be akin to a dynamic array and hence be 
incompatible.


Incompatible to what?

int[10] a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
a[0 .. 2] = a[2 .. 4];
assert(a[0] == 3);
assert(a[1] == 4);
int[10] b = void;
b[] = a[];
assert(b == [3, 4, 3, 4, 5, 6, 7, 8, 9, 10]);


struct SuperSpecializedArray(T, size_t S) if (S > 0)
{
   T[S] elements;

   struct SuperSpecializedArrayRange
   {
  typeof(elements) e;

  this(SuperSpecializedArray a)
  {
 e = a.elements; // copies
  }

  // ...
   }
}

Upon creation of a SuperSpecializedArrayRange, the array is 
copied, but more importantly, data which may not ever be needed 
is copied and that's supposed to be a big selling point for 
ranges - only ever touching the data when it's requested - am I 
wrong ?


Ranges need not be lazy. They can be, and most of them should be 
indeed, but they need not be. And, as you yourself point out, in 
your case `e` can just be a slice, and your range becomes lazy.


Re: How to ensure template function can be processed during compile time

2020-07-08 Thread Stanislav Blinov via Digitalmars-d-learn

On Wednesday, 8 July 2020 at 20:11:05 UTC, IGotD- wrote:


int v;

enum sz = mySize!int // works, returns 46
enum sz2 = mySize(v) // doesn't work. Error: variable v cannot 
be read at compile time


Here we have a difference between C++ and D as C++ was able 
infer the size of v during compile time.


To add to other respondents' replies, you can pass something that 
is known at compile time, for example the .init value:


int v;
enum sz2 = mySize(v.init);
static assert(sz2 == 46);

This way the compiler is able to evaluate `mySize` at compile 
time.


Or use an alias template argument:

auto mySize(alias v)()
{
return v.sizeof + 42;
}

int v;
enum sz = mySize!int;
enum sz2 = mySize!v;
static assert(sz == sz2);
static assert(sz == 46);


Re: constructing labels for static foreach inside switch inside foreach

2020-07-08 Thread Stanislav Blinov via Digitalmars-d-learn
On Wednesday, 8 July 2020 at 02:06:01 UTC, Steven Schveighoffer 
wrote:


Seems simple enough, except that this inner portion is 
unrolled, and if I have more than one type to run this on, I 
already have an "innerloop" label defined.


Is there a way to define a label using a mixin or something? or 
do I have to wrap this in a function?


Is there another way to approach this?


Can't you put a single label after your outer foreach and goto it?


Re: opApply and attributes

2020-07-07 Thread Stanislav Blinov via Digitalmars-d-learn

On Tuesday, 7 July 2020 at 13:33:41 UTC, Paul Backus wrote:


You can make opApply a template:

int opApply(Dg)(Dg dg)
if (is(Dg : scope int delegate(ref E)))
{
// etc.
}

Because `scope int delegate(ref E) @safe` implicitly converts 
to `scope int delegate(ref E)`, this version will accept both 
@safe and non-@safe delegates. (And likewise for the other 
function attributes.)


Yeah, but unfortunately then this won't work:


foreach(elem; test) {
assert(elem == key);
}


you'd have to spell out the types for `elem`.


Re: BetterC Bug? Intended Behavior? Asking Here As Unsure

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

On Monday, 6 July 2020 at 20:06:51 UTC, Kayomn wrote:
Something discovered in the D Language Code Club Discord server 
with the help of Wild is that the following code:


struct Test { ~this() {} }
void tester(Test test, Test[] tests...) { }

extern(C) void main() {
tester(Test(), Test());
}

Raises the "TypeInfo cannot be used with ~betterC" error. It 
seems to be due to an inclusion of both the destructor and the 
non-vararg and vararg argument matching from testing.


Anyone know a way around this without resulting to the rather 
hacky solution of just having 1 argument and always assuming 
that at least 1 argument is present?


Here is a code demo setup for demonstrating the potential 
problem:

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


This seems to compile:

struct Test { ~this() {} }
void tester(size_t n)(Test[n] tests...)
if (n > 0)
{}

extern(C) void main() {
tester(Test(), Test());
}

No assumptions, though `tester` does become a template.

I'd say the original error should be reported on bugzilla, if it 
isn't already; if only for the error message which is 
ridiculously obscure.


Re: Print only part of a stack trace

2020-07-01 Thread Stanislav Blinov via Digitalmars-d-learn

On Wednesday, 1 July 2020 at 18:30:15 UTC, Dennis wrote:

I have a function that checks a global error constant of a C 
library (OpenGL) like this:

```
void assertNoOpenGLErrors() {
if (glGetError() != GL_NO_ERROR) {
assert(0); // stack trace points to here instead of 
caller

}
}
```

And I would like to rewrite it to this:
```
void assertNoOpenGLErrors() {
if (glGetError() != GL_NO_ERROR) {
print(getStackTrace().filterTrace());
exit();
}
}
```


void assertNoOpenGLErrors(string file = __FILE__, int line = 
__LINE__, string func = __PRETTY_FUNCTION__)

{
if (glGetError() != GL_NO_ERROR) {
print(file, ":", line, ":", func, ": blah");
exit();
}
}

:)


Re: Progress printing with threads?

2020-07-01 Thread Stanislav Blinov via Digitalmars-d-learn

On Wednesday, 1 July 2020 at 07:52:28 UTC, AB wrote:
Hello. I am unsure how to proceed about printing progress in my 
program.

Is it a good idea to std.concurrency.spawn a new thread?..
This example code shows my situation:

MmFile  input   = new MmFile(/* ... */);
ulong   fileSize= input.length;

for (ulong i = 0; i < fileSize; ++i)
{
// ...
}


If you can only update the progress between iterations I don't 
see why you would use threads here. A timer should suffice:


import std.datetime.stopwatch;

MmFile  input   = new MmFile(/* ... */);
ulong   fileSize= input.length;
autosw  = StopWatch(AutoStart.yes);

for (ulong i = 0; i < fileSize; ++i)
{
  // ...
  if (sw.peek >= 2.seconds)
  {
  writefln("Progress: %5.2f%%", i*100.0/fileSize);
  sw.reset;
  }
}



Re: idiomatic output given -preview=nosharedaccess ,

2020-06-30 Thread Stanislav Blinov via Digitalmars-d-learn
On Tuesday, 30 June 2020 at 20:04:33 UTC, Steven Schveighoffer 
wrote:


The answer is -- update Phobos so it works with -nosharedaccess 
:)


Yeah... and dip1000. And dip1008. And dip... :)



Re: Privatize a few members to allow messing with them #11353

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

On Tuesday, 30 June 2020 at 19:58:05 UTC, matheus wrote:


+loc.linnum = loc.linnum + incrementLoc;

This works because it was declared:

void linnum(uint rhs) { _linnum = rhs; }

Right?


Almost. Given these definitions:

@safe @nogc pure @property
{
const uint linnum() { return _linnum; }
void linnum(uint rhs) { _linnum = rhs; }
}

This:

loc.linnum = loc.linnum + incrementLoc;

is rewritten as:

loc.linnum(loc.linnum() + incrementLoc);


Re: Privatize a few members to allow messing with them #11353

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

On Tuesday, 30 June 2020 at 19:42:57 UTC, matheus wrote:

in this case this was more a style thing than anything else 
right? Or is there something I'm not able to see?


Before the change, linnum and charnum are public variables, one 
can do a += on them. After the change, they become properties 
accessing, as the PR says, private variables:


@safe @nogc pure @property
{
const uint linnum() { return _linnum; }
const uint charnum() { return _charnum; }
void linnum(uint rhs) { _linnum = rhs; }
void charnum(uint rhs) { _charnum = rhs; }
}

...with which the += won't work (at least this variant, as the 
getter isn't returning ref).


Re: scope guard question

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

On Monday, 29 June 2020 at 22:31:12 UTC, Arjan wrote:

So when no inner scope is present, the scope exit 'runs' after 
the return? Is that indeed expected behavior according to the 
specification?


Yes. A scope ends at the '}'. Destructors and scope guards 
execute then, after the return.


Re: [DIP1000] Something I don't quite understand regarding 'scope'

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

On Monday, 29 June 2020 at 06:21:43 UTC, ag0aep6g wrote:

Since `local` and `writeln` are templates, the attributes for 
their parameters are inferred from their bodies. `local!(int*)` 
doesn't do anything with the parameter, so it's inferred as 
`scope`. `writeln!(int*)` apparently does something that 
prevents `scope` from being inferred.


Thanks. It would appear indeed that inference fails for some 
reason. Explicitly marking args as 'scope' for `writeln` and 
`File.write` lets them compile. I wonder if there's a way to find 
exactly what it is in either of those that prevents the compiler 
from inferring 'scope'.


Re: reference variables don't exist, but can simulate them

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

On Monday, 29 June 2020 at 02:11:15 UTC, NonNull wrote:

Deprecation: Cannot use alias this to partially initialize 
variable j of type refer. Use j._()


This is for the line j=3

What is this about? Where does this hidden rule come from?


That one comes from [1]. But there are quite a few more "hidden" 
rules that you're violating here. Try putting @safe on your main 
and compiling with -preview=dip1000 (for dmd, refer to your 
compiler's help if you're using others). The bulk of escape 
analysis is only done for @safe, and only with that DIP enabled 
(IIRC only some trivial checks are done otherwise).


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


[DIP1000] Something I don't quite understand regarding 'scope'

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

void local(Args...)(Args args)
{
}

void main() @safe
{
import std.stdio;
scope int* p;
local(p);   // Ok
writeln(p); // Error: scope variable p assigned to non-scope 
parameter _param_0 calling std.stdio.writeln!(int*).writeln

}

The signatures of `std.stdio.writeln` and `local` are the same 
(see `writeln` [1]). Yet, with '$ dmd -preview=dip1000' the call 
to `local` compiles, while the call to `writeln` doesn't.


Is that an instance of [2]?

[1] 
https://github.com/dlang/phobos/blob/v2.092.1/std/stdio.d#L3865

[2] https://issues.dlang.org/show_bug.cgi?id=20023


Re: How to implement Canceleable spawn() from parent

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

On Sunday, 28 June 2020 at 23:02:26 UTC, aberba wrote:


I believe this:

StopWatch sw;
sw.start;

works becuse D structs are initialized by default, right?
I've never actually done it this way. Little details.


Yup. You can also do a

auto sw = StopWatch(AutoStart.yes);

and not have to call `start` explicitly.


Re: How to implement Canceleable spawn() from parent

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

On Sunday, 28 June 2020 at 13:29:08 UTC, aberba wrote:


Getting error:

Error: template std.concurrency.spawn cannot deduce function 
from argument types !()(void delegate(Tid id) @system, Tid), 
candidates are:
/usr/include/dmd/phobos/std/concurrency.d(460,5):
spawn(F, T...)(F fn, T args)

  with F = void delegate(Tid) @system,
   T = (Tid)
  must satisfy the following constraint:
   isSpawnable!(F, T)



The error you're getting is because you're passing a pointer to a 
delegate instead of a delegate.



Tid id = spawn(, milliseconds, );

^ here

But fixing that still won't compile, because when you want to 
pass a delegate to `spawn`, it needs to be a shared delegate.


If I understood your intent correctly, here's how you can do it:

import std.stdio : writeln;
import std.concurrency;
import core.thread.osthread : Thread;
import std.datetime.stopwatch;

auto setInterval(long milliseconds, void function() callback)
{
static void worker(Duration d, void function() cb)
{
writeln("Starting ", thisTid, "...");

bool done = false;

StopWatch sw;
sw.start;
while (true)
{
// wait for messages for a timespan of at least `d`
receiveTimeout(
d,
(string text) {
   writeln("Received string: ", text);
   if (text == "cancel")
   done = true;
   });

if (done)
break;

// a non-cancelling message might've been received 
before timeout,

// so test if it's really time for the callback
if (sw.peek >= d)
{
cb();
sw.reset;
}
}
}

Tid id = spawn(, milliseconds.msecs, callback);

return id;
}

void stopInterval(Tid tid) {
send(tid, "cancel");
}

void main()
{
auto tid = setInterval(1000, { writeln("tick"); });
Thread.sleep(2.seconds);
send(tid, "not cancel");
Thread.sleep(5.seconds);
stopInterval(tid);
}


Re: Garbage collection

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

On Saturday, 27 June 2020 at 16:03:12 UTC, kinke wrote:
On Saturday, 27 June 2020 at 15:27:34 UTC, Stanislav Blinov 
wrote:



Hrm... What happens if you call collect() twice?


Nothing changes, even when collecting 5 times at the end of 
each iteration. In the filed testcase, I've extracted the stack 
ref to a dedicated function, so that there really shouldn't be 
any refs on the stack (this is unoptimized code after all...).


Here on Linux, the double collection results in this output:

  GC stats: 0M used, 0M free, 0M total
Starting
  string size: 943M
  GC stats: 0M used, 2306M free, 2306M total
Starting
  string size: 943M
  GC stats: 0M used, 2306M free, 2306M total
Starting
  string size: 943M
  GC stats: 0M used, 2306M free, 2306M total
Starting
  string size: 943M
  GC stats: 0M used, 2306M free, 2306M total


Re: Garbage collection

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

On Saturday, 27 June 2020 at 14:12:09 UTC, kinke wrote:

Note that I explicitly clear the `str` slice before 
GC.collect(), so that the stack shouldn't contain any refs to 
the fat string anymore.


Hrm... What happens if you call collect() twice?


Re: Garbage collection

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

On Saturday, 27 June 2020 at 11:35:12 UTC, Arafel wrote:

If you are using linux, have in mind that the memory is often 
not returned to the OS even after a (libc) free.


That's a good observation. Although a GC implementation is not 
required to actually use malloc, so depending on that falls into 
"know what you're doing" territory :)


Re: Garbage collection

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

On Saturday, 27 June 2020 at 11:11:38 UTC, James Gray wrote:


I am measuring the memory usage using top from the command line.
GC.minimize() does seem to stop the leak.


That is not a memory leak. That's the allocator keeping pages for 
itself to not have to go to the kernel every time you allocate.


But it doesn't explain why the program isn't releasing 
essentially all the memory between calls to f (it using around 
2GB ram all the time).


Allocators usually don't do that. They keep (at least some) 
memory mapped to make allocations more efficient.



Is there a way of achieving that?


I would think collect + minimize should do the trick. Just keep 
in mind that that's grossly inefficient.


Re: Garbage collection

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

On Saturday, 27 June 2020 at 10:08:15 UTC, James Gray wrote:

I find that the memory usage grows to about 1.5GB and never 
decreases. Is there something I am not understanding?


How are you measuring that? GC.collect() does not necessarily 
release the pages to the OS. For that, there's the GC.minimize().


Re: called copy constructor in foreach with ref on Range

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

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


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

[...]

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


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


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


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


Re: called copy constructor in foreach with ref on Range

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

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


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


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


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

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

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


Conceptually:

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

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


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


??? `move` infers.

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


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


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


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


You mean this?

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

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

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

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


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


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


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


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


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




Re: called copy constructor in foreach with ref on Range

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

On Tuesday, 23 June 2020 at 02:41:55 UTC, Jonathan M Davis wrote:

As things stand, uncopyable ranges aren't really a thing, and 
common range idiomns rely on ranges being copyable.


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


We'd need some major redesigning to make uncopyable ranges 
work, and personally, I don't think that it's worth the trouble.


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


The range API has no requirement that the init value of a range 
be empty, and any generic code which relies on such behavior is 
buggy. In the case of classes, it would outright crash, because 
the init value would be null.


Yeah, that's a shame.

I agree that ideally the range API would require that the init 
state of a range be a valid, empty range, but that's simply not 
how it works right now. In order to make it work that way, we'd 
have to redesign the range API in at least some respects (e.g. 
getting rid of save and making it illegal for classes to be 
forward ranges).


Better yet - making it illegal for classes to be ranges.

As things stand, it is _not_ true that it's safe to copy 
forward ranges and then use the original. Sure, it will work 
for some ranges, but for others it won't. The entire reason 
that save exists is for ranges that are classes, because 
copying them does not result in an independent range. The range 
API does not require that copying a range result in an 
independent copy. It's not even guaranteed that copying a range 
that's a struct will result in an indpendent copy. Depending on 
the range type, copying it could result in an independent copy, 
or it could result in a reference to to the original range, or 
it could even result in part of the state being copied and part 
of it being a reference (e.g. if the current front is stored 
directly in the range, but the iteration state is stored by 
reference).


If copying isn't making a copy, it's not copying.

If you rely on copying a range resulting in an independent 
copy, you will have buggy code - even if it's a forward range. 
The _only_ way that the range API specifies that you can get an 
independent copy of a range is to use save, and generic code 
should never rely on any other mechanism for that.


That's exactly what I said. "Copying of forward ranges is 
absolutely fine. It's what the current `save()` primitive is 
supposed to do."
...Except, of course, that that shouldn't be the case. *Copying* 
should be creating a copy. :)


Now, ideally, we'd get rid of save and require that copying a 
forward range result in an independent copy (which would then 
require that a class be wrapped in a struct to be a range)


Yes!


but that's simply not how the current range API works.


No, it's not :(


Re: called copy constructor in foreach with ref on Range

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

On Monday, 22 June 2020 at 21:33:08 UTC, H. S. Teoh wrote:

Don't be shocked when you find out how many Phobos ranges have 
.init states that are invalid (e.g., non-empty, but .front and 
.popFront will crash / return invalid values).


Which ones?

Jonathan is coming from the POV of generic code.  The problem 
with move leaving the original range in its .init state isn't 
so much that it will crash or anything (even though as you said 
that does indicate a flaw in the range's implementation), but 
that the semantics of generic code changes in subtle ways.


Well that means that the code is not generic, i.e. the bug 
originates in the design, not implementation.



auto myGenericFunc(R)(R r) {
...
foreach (x; r) {
doSomething(x);
}
if (!r.empty)
doSomethingElse(r);
...
}

Suppose for argument's sake that the above foreach/if structure 
is an essential part of whatever algorithm myGenericFunc is 
implementing. Now there's a problem, because if R has 
array-like semantics, then the algorithm will do one thing, but 
if R has reference-like or move semantics, then the behaviour 
of the algorithm will be different, even if both ranges 
represent the same sequence of input values.


Yep, definitely not generic. Which is exactly the kind of error 
that should be caught at compile time. Which we, sadly, can't do 
with the current range API.



consider a function that drops the first n elements of a range.
Your generic function might want to pop the first n elements 
then do something else with the rest of the range.  Well, if 
you write it the obvious way:


auto myAlgo(R)(R r) {
size_t n = ...;
dropFirstN(r, n);
... // do something else with r
}

then you have a subtle bug, because the state of r after the 
call to dropFirstN might be completely different depending on 
whether r behaves like an array or like a by-reference or move 
type.


Err... that one is actually fine. It would take the range by ref 
and pop off the elements. There already is such a function - the 
popFrontN. It's the functions that take ranges by value that 
present the not-so-subtle issue with reference types. For 
example, its chainable would-be-counterpart drop(). "Would-be" 
because that one takes the argument by value.
We should move toward disallowing reference types to be ranges. A 
good deal of the rest can be solved with API and design changes 
(like disallowing copying of input ranges).


It's kind of interesting how, with the ongoing discussion about 
range API in the general forum, a couple of range questions are 
brought up in learn. Something, as they say, is in the air.


Re: Temporary File Creation

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

On Monday, 22 June 2020 at 21:46:57 UTC, Per Nordlöw wrote:
Has anybody written a procedure for creating a temporary file 
in a race-free manner?


And why has such a procedure not already been added to std.file 
when std.file.tempDir has?


See: https://dlang.org/library/std/file/temp_dir.html


tempDir just returns a path (i.e. "/tmp" or whatever it is on 
Windows, etc.), it doesn't create anything.


Given the synopsis of std.file, a procedure for *creating* a file 
doesn't belong there, as it would only be half of an operation.


There is a https://dlang.org/library/std/stdio/file.tmpfile.html


Re: called copy constructor in foreach with ref on Range

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

On Monday, 22 June 2020 at 20:51:37 UTC, Jonathan M Davis wrote:

You're unlikely to find much range-based code that does that 
and there really isn't much point in doing that. Again, copying 
isn't the problem. It's using the original after making the 
copy that's the problem.


Copy *is* the problem. If you can't make a copy (i.e. you get a 
compilation error) - you don't have a problem, the compiler just 
found a bug for you. Sadly, historically D's libraries were built 
around lots of redundant copying, even though there are very few 
cases where copies are actually required. The reason why we're 
"unlikely to find much range-based code that does that [move]" is 
(a) sloppy or shortsighted design and (b) poor language support. 
The latter hopefully stands to change.


And moving doesn't fix anything, since the original variable is 
still there
(just in its init state, which would still be invalid to use in 
generic code and could outright crash in some cases if you 
tried to use it - e.g. if it were a class reference, since it 
would then be null).


Eh? A range in 'init' state should be an empty range. If you get 
a crash from that then there's a bug in that range's 
implementation, not in user code.


So, code that does a move could accidentally use the original 
range after the move and have bugs just like code that copies 
the range has bugs if the original is used after the copy has 
been made. So, the rule of thumb is not that you should avoid 
copying ranges. It's that once you've copied a range, you 
should then use only the copy and not the original.


That is not true. Copying of forward ranges is absolutely fine. 
It's what the current `save()` primitive is supposed to do. It's 
the copying of input ranges should just be rejected, statically.


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

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

On Monday, 22 June 2020 at 19:55:29 UTC, mw wrote:


Yes, in the same order and of the same length.


Can we add this information to the doc? to make it clear to the 
user:


https://dlang.org/library/std/traits.html


It's pretty clear in that doc already:

alias FieldNameTuple(T) = 
staticMap!(NameOf,T.tupleof[0..__dollar-isNested!T]);

alias Fields(T) = typeof(T.tupleof[0..__dollar-isNested!T]);

But if you'd like it spelled out in text as well, you can make a 
PR for the Phobos repository.


Re: Why infinite loops are faster than finite loops?

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

On Saturday, 20 June 2020 at 21:11:57 UTC, tastyminerals wrote:
I am not sure that this is a question about D or a more general 
one. I have watched this nice presentation "Speed Is Found In 
The Minds of People" by Andrei: 
https://www.youtube.com/watch?v=FJJTYQYB1JQ=youtu.be?t=2596 and on 43:20 he says that "push_heap" is slow because of structured loops and finite for (throughout the presentation Andrei shows algorithm examples with infinite loops). I wonder why is that? Is it because the finite loop needs to keep track of the number of iterations it performs? Wouldn't the compiler optimize it better than the infinite one because it knows the number of iterations the for loop needs?


He explains it there and then. When the number of iterations is 
*small*, overhead of each iteration can be significant. He's not 
talking about known *number* of iterations, but known exit 
conditions. If you put those exit conditions in the loop's test, 
you have to go through till the end and then test them, while if 
you put the tests in the loop body you can bail early and skip 
some unnecessary operations.


Don't take it too literally. As he himself says "always use 
infinite loops, except in most cases" :)


He's simply emphasizing the importance of looking at code 
critically and not taking things for granted.


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

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

On Saturday, 20 June 2020 at 20:17:54 UTC, mw wrote:
Are their returned value, i.e the field names and their types 
are always in the same order, and of the same length?


If they are not, how to get sync-ed pairs (name, type)?

If they are, why we need two separate calls, which cause 
confusion.


Yes, in the same order and of the same length. You need two 
because they're not calls (and the results are not "return 
values"), they're tuples constructed out of compile-time type 
information, and the former (FieldNameTuple) has to generate new 
symbols, which may not be desirable in cases when you don't need 
the names.


Re: "if not" condition check (for data validation)

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

On Thursday, 18 June 2020 at 17:39:44 UTC, Denis wrote:

I should add that this one made me laugh though, giving 
flashbacks to that horrible "not speak" of the early 90s:


  if ( configfile.isFile.not ) ...

LOL


Approve Yoda does.


Re: "if not" condition check (for data validation)

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

On Thursday, 18 June 2020 at 13:57:39 UTC, Dukc wrote:


No reason to use templates here


Pff. Me no think straight. -.-


Re: "if not" condition check (for data validation)

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

On Thursday, 18 June 2020 at 12:13:21 UTC, Denis wrote:


THE ESSENTIAL QUESTION

Is there a way to write an `unless` operator that would allow 
the condition to be expressed in an affirmative sense? It would 
be used like `if`, i.e. something like:


   unless (  ) {
 ; // Or even: 
 continue; }

Templates offer a clean syntax, but I can't come up with a way 
to use them for a conditional operator. Mixins are flexibile, 
but I suspect the result would not be very readabile (that is, 
less readable even than "if ( ! (..." ). I was hoping that some 
feature, or combination of features, in D might allow this to 
be achieved.


No, there isn't a way to write an operator. And yes, with 
templates you could do something like


auto not(alias cond)() { return !cond(); }

if (not!(() => abra && cadabra)) ...

but that is indeed even less readable.


Re: "if not" condition check (for data validation)

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

On Wednesday, 17 June 2020 at 23:46:54 UTC, Denis wrote:
`if` is not a good substitute, because it works in the opposite 
sense, often requiring lots of `not`s. As a trivial example:


  assert( configfile.isFile && configfile.extension == ".conf" )
-vs-
  if ( !configfile.isFile || configfile.extension != ".conf" )



A BETTER SOLUTION ???

I haven't been able to come up with another option that is more 
efficient yet doesn't sacrifice readability. I would welcome 
suggestions.


Thanks in advance.
Denis


if( ! (configfile.isFile && configfile.extension == ".conf") )

?


Re: Should a parser type be a struct or class?

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

On Wednesday, 17 June 2020 at 11:50:27 UTC, Per Nordlöw wrote:
Should a range-compliant aggregate type realizing a parser be 
encoded as a struct or class? In dmd `Lexer` and `Parser` are 
both classes.


In general how should I reason about whether an aggregate type 
should be encoded as a struct or class?


What's a range-compliant aggregate type? Ranges are typically 
views of someone else's data; an owner of the data woulnd't store 
mutable iterators, and won't be a range. For that reason also, 
ranges are structs, as most of them are thin wrappers over a set 
of iterators with an interface to mutate them.


If you *really* need runtime polymorphism as provided by the 
language - use a class. Otherwise - use a struct. It's pretty 
straightforward. Even then, in some cases one can realize their 
own runtime polymorphism without classes (look at e.g. Atila 
Neves' 'tardy' library).


It's very easy to implement a lexer as an input range: it'd just 
be a pointer into a buffer plus some additional iteration data 
(like line/column position, for example). I.e. a struct. Making 
it a struct also allows to make it into a forward range, instead 
of input range, which is useful if you need lookahead:


struct TokenStream
{
this(SourceBuffer source)
{
this.cursor = source.text.ptr;
advance(this);
}

bool empty() const
{
return token.type == TokenType.eof;
}

ref front() return scope const
{
return token;
}

void popFront()
{
switch (token.type)
{
default:
advance(this);
break;
case TokenType.eof:
break;
case TokenType.error:
token.type = TokenType.eof;
token.lexSpan = LexicalSpan(token.lexSpan.end, 
token.lexSpan.end);

break;
}
}

TokenStream save() const
{
return this;
}

private:

const(char)* cursor;
Location location;
Token token;
}

, where `advance` is implemented as a module private function 
that actually parses source into next token.


DMD's Lexer/Parser aren't ranges. They're ourobori.


Re: Initializing an associative array of struct

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

On Sunday, 14 June 2020 at 04:36:09 UTC, Denis wrote:


Note also that the defaults for id and value are fine...


I would welcome a suggestion for how to initialize the keys of 
parameters. As there will be a couple dozen of the param string 
keys, a more succinct method would be preferable over a verbose 
one.


Param[string] parameters;
string[] keys =
[
"huh", "buh", "hrm", "pff", "err", "ack", "ugh",
/* ... */
"zzz"
];
foreach (k; keys)
parameters.require(k);

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

The `require` function, when called only with key, will insert 
default (.init) value for that key.


Re: Weird behavior with UDAs

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

On Saturday, 13 June 2020 at 13:08:29 UTC, realhet wrote:

How can be a string represented with 'null' by default instead 
on `""`. Unless I state it explicitly with name="" ? o.O


Because string is simply `alias string = immutable(char)[]`, and 
default initializer for arrays is null.


Re: Why is it possible to call non-const member functions of rvalues but a compile error to modify members or rvalues directly?

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

On Saturday, 13 June 2020 at 11:26:58 UTC, Johannes Loher wrote:

Why is it a compile error to set `_a` directly but calling `a` 
just works fine?


If we prevent modifying members of rvalues directly, I would 
also expect calling non-const member functions of rvalues to be 
prevented.


1) Constructors and destructors are also member functions. Surely 
you won't suggest making all constructors `const`, and not being 
able to destruct a temporary? :)
2) The member functions may have useful side effects even on the 
state of temporary.

3) The member functions may serve as factories.

The temporary exists until the end of full expression, or until 
the end of enclosing statement. It is simply not an lvalue for 
the caller, but it certainly exists, and so its interface must 
function. Consider (this code will fail on older compilers, up to 
2.067.0, due to a bug):


void main()
{
import std.stdio : File;
import std.range : iota;
with (File("test.txt", "w"))
{
foreach (n; iota(1, 100, 5))
writeln(n);
}
}

This will open the file, write numbers [1, 96] on their own lines 
in that file, and close it. Both the File and the Iota range are 
temporaries. File can't be `const` as it's a wrapper over FILE*. 
The range can't be const since the foreach mutates it, and it is 
effectively a factory of numbers.




Re: Finding out ref-ness of the return of an auto ref function

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

On Saturday, 13 June 2020 at 09:13:36 UTC, Arafel wrote:

If, however, you're wrapping a function template, however, you 
won't know until you actually instantiate it, which is 
basically going back to Paul Backus' solution. So the compiler 
doesn't always have all the information :)


Well, the compiler can know `typeof (return)`, so at that point 
and under the same circumstances it has know (and thus it could 
expose) the ref-ness.


And it does, for functions, via the aforementioned trait. It 
can't for templates until those templates are instantiated, which 
you can only do correctly by actually forwarding arguments to it 
(because a function template may have auto ref parameters).


Steven's issue report doesn't account for templates, nor 
overloading, and correctly testing the latter would pretty much 
require you to match argument types and ref-ness by hand anyway 
(yuck).


Re: Finding out ref-ness of the return of an auto ref function

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

On Friday, 12 June 2020 at 17:50:43 UTC, Arafel wrote:

All in all, I still think something like 
`__traits(isRef,return)` would still be worth adding! After all 
the compiler already has all the information, so it's just 
about exposing it. I'm trying to think of a library solution, 
but I find it very hard to express "the hypothetical result of 
calling the current function with the current parameters in the 
current context".


A.


If you're wrapping a function you can use a 
'getFunctionAttributes' trait [1], which would contain a "ref" if 
that function returns ref.


If, however, you're wrapping a function template, however, you 
won't know until you actually instantiate it, which is basically 
going back to Paul Backus' solution. So the compiler doesn't 
always have all the information :)


[1] https://dlang.org/spec/traits.html#getFunctionAttributes


Re: filter custom version id from __traits code

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

On Tuesday, 9 June 2020 at 17:40:10 UTC, Basile B. wrote:


Any idea ?


As I replied in the issue report:


Instead of

static if (!is(mixin(member) == module) && !(is(mixin(member

use

static if (is(typeof(mixin(member


Re: Error: llroundl cannot be interpreted at compile time, because it has no available source code

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

On Monday, 8 June 2020 at 18:08:57 UTC, mw wrote:

2) even it does so, but why such simple function as lroundl 
cannot be CTFE-ed?


Because, as the error message states, there's no source for it :) 
std.math calls into C math library.


Re: Arrays and non-copyable elements

2020-06-07 Thread Stanislav Blinov via Digitalmars-d-learn
On Monday, 8 June 2020 at 00:31:10 UTC, Steven Schveighoffer 
wrote:


This is a bug, please file. What is likely happening is that 
the template is not moving the data to the underlying C call.


-Steve


That is not a bug, it's a shortcoming of garbage-collected 
arrays. D arrays are not equipped to deal with non-copyable 
values. The ~= has to expect to copy contents of arr, since at 
runtime there may be multiple references to it, i.e:


auto storage = [NonCopyable(a), /*  */];
auto arr = storage[1 .. 3];

arr ~= NonCopyable(n);

This would need to allocate a new array and copy contents of 
storage[1 .. 3] into it.


Re: Should it compile?

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

On Sunday, 7 June 2020 at 23:09:41 UTC, Jack Applegame wrote:

auto const_ua = Unique!(const NonCopyable)(move(ca)); // 
error, why???

}
```


Moving *from* a const would violate const. At least, until such 
time that the compiler is finally taught about move() (hopefully, 
sometime this decade).


`move` and `moveEmplace` take arguments by ref. Therefore, if you 
call them with a const lvalue, arguments will be ref const. Which 
are allowed to bind to both mutable, const *and*  immutable, and 
implementations of `move` and `moveEmplace` are not able to 
assume either way. Const is const.


`emplace` violates const (it has to). Perhaps `moveEmplace` 
should also be allowed to violate const for its *second* 
argument, but not the first, on the assumption that the 
programmer knows what they're doing.


Problem here is that, well, it wouldn't be as straightforward as 
it sounds, because the language allows overloading constructors 
based on `const` and `immutable`. So you may end up moving into a 
const such state that that const is not equipped to deal with:


struct S {
private { int i; bool iAmConst; }
this(int i) { this.i = i; }
this(int i) const { this.i = i; iAmConst = true; }
}

S mutableS = 42;
const S constS = void;
moveEmplace(mutableS, constS); // if this was allowed, now what?
assert(constS.iAmConst);   // <- this would fail

An attempt was made to solve this (albeit the intended use case 
was different - impure moves), via DIP1014 and opPostMove. The 
DIP was even accepted. But apparently, it failed, for the above 
reason.


Here's hoping that move constructors do make it into the 
language, so that these darker places of the standard library (or 
rather, runtime nowadays) may die in peace.


Re: Should it compile?

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

On Saturday, 6 June 2020 at 12:54:38 UTC, Stanislav Blinov wrote:


The moveEmpalce should compile...


But not when the *first* argument is const though, like in the 
example. For *that*, one would have to insert an additional cast.


Re: Should it compile?

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

On Saturday, 6 June 2020 at 11:58:06 UTC, Basile B. wrote:

On Saturday, 6 June 2020 at 08:55:20 UTC, Jack Applegame wrote:

Should it compile?
I think, it should.


maybe it shouldn't but then with another message, for example

Error, cannot `void` initialize a `const` declaration.

since that makes very little sense, at least as a local 
variable. (as a member, this can be initialized in a 
constructor)


The moveEmpalce should compile, just like this does:

import std.conv : emplace;

emplace(, 'a');

But, in the case of emplacing into a const, either should be 
@system (moveEmplace is always @system, but `emplace` for this 
case is not at the moment).


One could do a

emplace(, move(b))

but that's more moves (and I believe current emplace even would 
insert a spurious copy there).


This is what we get for delegating emplacement and moves into a 
library instead of having appropriate intrinsics.


Re: Making alias of a struct field needs "this".

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

On Tuesday, 2 June 2020 at 09:28:01 UTC, realhet wrote:


I did it that way:
  private enum fieldMap = [ // simple names for descriptive and 
structured fields

"hauteur"   : "general.height",
"rayon" : "profile.radius",
"plage" : "profile.plage",
"offsetv"   : "profile.verticalOffset",
"offseth"   : "profile.horizontalOffset",
"varrad0"   : "profile.linearVariationBottom",
"varrad1"   : "profile.linearVariationTop",
"amplitude" : "periphery.amplitude",
"varlin0"   : "periphery.linearVariationBottom",
"varlin1"   : "periphery.linearVariationTop",
"varsinp"   : "periphery.cosinusVariationPlage",
"varsino"   : "periphery.cosinusVariationOffset",
"periodes"  : "periphery.nbPeriods",
"revolution": "periphery.turn"
  ];

  static foreach(k, v; fieldMap){ mixin("@property auto $() 
const{ return #; }".replace("$", k).replace("#", v)); } //I 
know, i know -> AliasSeq :D


But it doesn't look nice.


Try UDAs instead of a map:

struct A {
struct G {
@("hauteur") int height;
}
struct P {
@("rayon")   int radius;
@("plage")   int plage;
@("offsetv") int verticalOffset;
@("offseth") int horizontalOffset;

int noShortcut;

@("varrad0") int linearVariationBottom;
}

G general;
P profile;
/* ... */
static foreach (i, m; typeof(this).tupleof)
static foreach (j, f; typeof(m).tupleof)
static if (__traits(getAttributes, f).length)
mixin("@property auto ", __traits(getAttributes, 
f)[0], "() const { return this.tupleof[i].tupleof[j]; }");

}

pragma(msg, __traits(allMembers, A));



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

2018-12-16 Thread Stanislav Blinov via Digitalmars-d-learn

On Sunday, 16 December 2018 at 04:02:57 UTC, Q. Schroll wrote:
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


I know. What I mean is (what you left out) the language can't 
statically check that, so even if you were to violate the spec in 
that regard, you won't get any help from the compiler, and only a 
little from a handful of library functions. At runtime.


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

2018-12-13 Thread Stanislav Blinov via Digitalmars-d-learn

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. And even though it can't be statically checked, 
move and swap do actually perform this check at runtime in debug 
builds.
Operating under that rule, it should be legal to move any values 
that are passed to you. In fact, I postulate that it *must* be 
done instead of making copies. Unfortunately, Phobos doesn't 
agree.


struct S {
int x;
this(this) { x++; }
}

import std.stdio;

writeln(S.init);

I would expect that to print S(0). However, it doesn't, which is 
sad.


And, what if it's "this()(auto ref T value)"? Then moving could 
be dangerous if the parameter was passed as a ref. Or maybe it 
just wouldn't compile?


In that case moving indeed could be dangerous since you'd be 
modifying caller's state. A workaround is indeed to have 
different signatures or use `auto ref`. The constructor example 
in this thread doesn't fully address the difference between 
copying and moving though, because it's dealing with 
initialization. A more practical example is an actual container, 
like an array (simplified for brevity):


struct Array(T) {
T[] memory;
size_t size;

void append()(auto ref T x) {
static if (__traits(isRef, x)) {
import std.conv : emplace;
// copy-construct. Note that this is different than 
doing

// memory[size++] = x;
// because that will call opAssign instead of 
initializing + postblit

emplace([size++], x);
} else {
import std.algorithm.mutation : moveEmplace;
moveEmplace(x, memory[size++]);
}
}
}

That's different from the example being discussed, since 
assignment inside a constructor gets special treatment:


struct Container(T) {
T data;
this()(auto ref T x) {
static if (__traits(isRef, x))
data = x; // this assignment is initialization, so 
emplace is not needed, copy is being made

else
moveEmplace(x, data);
}
}


Re: How to get a function name (string) @ compile time

2018-12-09 Thread Stanislav Blinov via Digitalmars-d-learn
On Sunday, 9 December 2018 at 03:29:27 UTC, Andrew Pennebaker 
wrote:


Er, when I try to use either foo.stringof, or 
__trait(identifier, foo), I always get that binding name, 
rather than the original function name, sad panda.


I can only print out the current variable name, but I want to 
print the name of the function declaration, no matter how 
deeply I pass that first function pointer into different calls 
:/


You're confusing function pointer with the function symbol. This 
will not give you the function name:


import std.stdio;

void wrap(F)(F f) { writeln(__traits(identifier, f)); }
int foo() { return 0; }
void main() { wrap(); }

But this will:

import std.stdio;

auto wrap(alias f, Args...)(auto ref Args args) {
import std.functional : forward;
writeln("Calling ", __traits(identifier, f));
return f(forward!args);
}

int foo() { return 42; }
size_t bar(string x) { return x.length; }

void main() {
assert(wrap!foo == 42);
assert(wrap!bar("hello") == 5);
}



Re: int[] as constructor

2018-12-05 Thread Stanislav Blinov via Digitalmars-d-learn

On Tuesday, 4 December 2018 at 23:28:42 UTC, H. S. Teoh wrote:

Well OK, for int[] it's kinda silly 'cos that's the default, 
but in my code I've often had to write things like:


auto z = cast(float[]) [ 1.0, 2.0, 3.0 ];


Err,

auto z = [ 1.0f, 2, 3 ];

?


Re: version(StdDoc)

2018-11-25 Thread Stanislav Blinov via Digitalmars-d-learn

On Sunday, 25 November 2018 at 21:38:43 UTC, H. S. Teoh wrote:

Actually, I just thought of a way to do this with the existing 
language: use a struct to simulate an enum:


struct E {
alias Basetype = int;
Basetype impl;
alias impl this;

enum a = E(1);
enum b = E(2);
version(Windows) {
enum c = E(3);
}
version(Posix) {
enum c = E(4);
enum d = E(100);
}
}


Heh, that can work in a pinch. Disgusting though :D

It's not 100% the same thing, but gets pretty close, e.g., you 
can reference enum values as E.a, E.b, you can declare 
variables of type E and pass it to functions and it implicitly 
converts to the base type, etc..


There are some differences, like cast(E) won't work like an 
enum...


It should, you can cast values of same sizeof to a struct.

and .max has to be manually declared, etc.. You'll also need to 
explicitly assign values to each member, but for OS-dependent 
enums you have to do that already anyway.


Yeah, those aren't a huge concern for that particular scenario.


Re: dip1000 rule 5

2018-11-25 Thread Stanislav Blinov via Digitalmars-d-learn

On Sunday, 25 November 2018 at 21:22:09 UTC, sclytrack wrote:

Did DIP1000 go through any review process? I'm seeing it is a 
draft.


Review links are at the very end.


https://github.com/dlang/DIPs/blob/master/PROCEDURE.md

Keeps talking about a Drafts subdirectory. I don't see any 
directory named "Drafts".


Not sure about that one. Maybe Mike Parker could elaborate on 
this.


Re: Convert multibyte `string` to `dstring`

2018-11-25 Thread Stanislav Blinov via Digitalmars-d-learn
On Sunday, 25 November 2018 at 21:23:31 UTC, Vladimirs Nordholm 
wrote:


Is there a proper way to convert a string with multibyte 
characters into a dstring?


void main() {
import std.conv : to;
import std.stdio : writeln;
string a = "abc123";
auto b = to!dstring(a);
assert(b.length == 7);
writeln(b);
}


Re: dip1000 rule 5

2018-11-25 Thread Stanislav Blinov via Digitalmars-d-learn

On Sunday, 25 November 2018 at 19:22:36 UTC, sclytrack wrote:

There are 4 rules listed.
...
What is rule 5?
...
Wouldn't you call it D3 because of the name mangling of DIP1000 
once activated by default?


That "rule 5" looks like a straight up mistake. As for D3... 
IMHO, no, not by a long shot. There's 1014 and 1016, 1008, 
there's `shared`, there are improved move-assignments, there's 
`__mutable` and `@__future`, there are tons of issues in 
Bugzilla, the standard library is long overdue for a huge 
look-over...


Re: version(StdDoc)

2018-11-24 Thread Stanislav Blinov via Digitalmars-d-learn
On Sunday, 25 November 2018 at 07:19:50 UTC, Stanislav Blinov 
wrote:



Granted, it may require some special syntax, i.e.

enum E {
a,
b if version(Windows),
c if version(Windows),
d if version(Posix),
}

or something to that effect.


Come to think of it, since UDAs are now allowed, the compiler 
could potentially be taught this:


enum E {
a,
@version(Windows) b,
@version(Windows) c,
@version(Posix)   d,
}


Re: version(StdDoc)

2018-11-24 Thread Stanislav Blinov via Digitalmars-d-learn

On Sunday, 25 November 2018 at 05:41:56 UTC, H. S. Teoh wrote:
On Sat, Nov 24, 2018 at 05:48:16PM +, Stanislav Blinov via 
Digitalmars-d-learn wrote:



Yup. UDAs did get in there eventually, and version should too.


I think this would be a trivial DIP, by making it such that a 
version block inside an enum would lower to the above code. Of 
course, it could be taken further: the above trick doesn't 
quite handle this case:


enum E {
a,
version(Windows) {
b, c
}
version(Posix) {
d
}
}


That is what Jonathan (and I concur) is talking about.

But this looks like such an antipattern that it probably should 
be written differently anyway, or just generated via a string 
mixin.


Why is it an antipattern? Having to version the whole enum just 
because some stupid C API has two out of a hundred items 
versioned per platform is an antipattern :)


Granted, it may require some special syntax, i.e.

enum E {
a,
b if version(Windows),
c if version(Windows),
d if version(Posix),
}

or something to that effect. But there has to be a better way 
than just versioning the whole enum or resorting to clumsy mixins.


Re: version(StdDoc)

2018-11-24 Thread Stanislav Blinov via Digitalmars-d-learn
On Saturday, 24 November 2018 at 17:43:35 UTC, Jonathan M Davis 
wrote:
On Saturday, November 24, 2018 9:28:47 AM MST Stanislav Blinov 
via Digitalmars-d-learn wrote:

On Saturday, 24 November 2018 at 07:00:31 UTC, Jonathan M Davis

wrote:
> [not legal]
>
> enum Foo
> {
>
> a,
> b,
> version(linux) c = 42,
> else version(Windows) c = 54,
>
> }
>
> You're forced to version the entire enum.

Not in this case, no:

enum Foo
{
 a,
 b,
 c = {
version(linux) return 42;
else version(Windows) return 54;
 } ()
}

/pedantry


LOL. That's an interesting trick. It's ugly and hacky, but it 
does work around the problem.


:)

I'm still inclined to think though that it should be legal to 
just use version directly in the member list.


Yup. UDAs did get in there eventually, and version should too.


Re: version(StdDoc)

2018-11-24 Thread Stanislav Blinov via Digitalmars-d-learn
On Saturday, 24 November 2018 at 07:00:31 UTC, Jonathan M Davis 
wrote:



[not legal]

enum Foo
{
a,
b,
version(linux) c = 42,
else version(Windows) c = 54,
}

You're forced to version the entire enum.


Not in this case, no:

enum Foo
{
a,
b,
c = {
   version(linux) return 42;
   else version(Windows) return 54;
} ()
}

/pedantry


Re: How to iterate getSymbolsByUDA

2018-11-24 Thread Stanislav Blinov via Digitalmars-d-learn

On Saturday, 24 November 2018 at 03:48:12 UTC, Eko Wahyudin wrote:

Hi all,
anyone know how to iterate getSymbolsByUDA ?


enum Attr;
struct A
{
@Attr int a;
int b;

@Attr void foo() {}
@Attr void foo(int) {}
}

void main() {
import std.traits;
import std.stdio;

alias symbols = getSymbolsByUDA!(A, Attr);

A a;

static foreach (i; 0 .. symbols.length) {
writeln("identifier: ", __traits(identifier, symbols[i]));
static if (is(typeof(symbols[i]) == int)) {
__traits(getMember, a, __traits(identifier, 
symbols[i])) = 42;

}
}

assert(a.a == 42);
}



Re: D vs perl6

2018-11-22 Thread Stanislav Blinov via Digitalmars-d-learn
On Thursday, 22 November 2018 at 09:03:19 UTC, Gary Willoughby 
wrote:

On Monday, 19 November 2018 at 06:46:55 UTC, dangbinghoo wrote:
So, can you experts give a more comprehensive compare with 
perl6 and D?


Sure!

1). You can actually read and understand D code.


Made my day. Thank you :)


Re: Throwing constructors and member destructors

2018-11-20 Thread Stanislav Blinov via Digitalmars-d-learn
On Tuesday, 20 November 2018 at 13:28:21 UTC, Boris-Barboris 
wrote:
On Tuesday, 20 November 2018 at 13:20:08 UTC, Stanislav Blinov 
wrote:

https://dlang.org/changelog/2.083.0.html#reboot14246


Nvm, found the info in the issue tracker, thank you for the 
link.


You're welcome. It's one of those problems that were out there 
for ages, and luckily it now is getting attention.


Re: Throwing constructors and member destructors

2018-11-20 Thread Stanislav Blinov via Digitalmars-d-learn
On Tuesday, 20 November 2018 at 13:01:40 UTC, Boris-Barboris 
wrote:

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

Notice no "B destructor" line in stdout.

Just got bitten by the assumption that my Buffer struct that 
transactionally aquires multiple external resources in 
constructor will rollback via member destructors that were 
successfully completed before the throw.


Can I get a clarification about current semantics? Should I 
essentially never throw in constructors if I want to rely on 
scope-based RAII?


And before we start a 10-page argument about the ideology of 
constructors, I would mostly just like to hear that this is 
documented somewhere, because I have certanly missed it.


https://dlang.org/changelog/2.083.0.html#reboot14246


Re: What is best way to read and interpret binary files?

2018-11-20 Thread Stanislav Blinov via Digitalmars-d-learn

On Tuesday, 20 November 2018 at 11:54:59 UTC, welkam wrote:
On Monday, 19 November 2018 at 22:14:25 UTC, Neia Neutuladh 
wrote:


Nothing stops you from writing:

SomeStruct myStruct;
fd.rawRead((cast(ubyte*))[0..SomeStruct.sizeof]);

Standard caveats about byte order and alignment.


Never would I thought about casting struct to static array. If 
I understood correctly you cast myStruct pointer to ubyte 
pointer and then construct static array on stack with 
tmpArray.ptr = (ubyte pointer) and tmpArray.sizeof = 
SomeStruct.sizeof


Almost correct, except it's not a static array, it's just a 
slice, i.e. ubyte[].


Re: difficulties with const structs and alias this / template functions

2018-11-19 Thread Stanislav Blinov via Digitalmars-d-learn
On Monday, 19 November 2018 at 14:51:14 UTC, Steven Schveighoffer 
wrote:



Or just use inout. This is literally what inout is for:

inout(q32) toQ32 inout {
return q32(x);
}

This should transfer whatever constancy of the original is used 
for the return value.


Yep, I just wanted to explicitly point out the `this T`, which 
gets overlooked way too often.


However, I'd state that this is really a workaround for a 
language deficiency. In reality, I would surmise (without 
knowing the implementation) that q32's state is a complete copy 
of the q16 state. So there is no reason to apply any constancy 
copying from the source to the destination.
The real problem is that mutating operators on struct rvalues 
are always allowed, because `this` is always passed by 
reference. For the most part this is a harmless drawback, but 
because there is no way to "opt out" of this, you can't stop it 
when it really doesn't make sense (as in this case).


Sure. At first I was perplexed why Dennis' a /= 2 even compiled. 
Then I saw the alias this.


I have long wanted a way to direct IFTI how to define its 
parameters base on the arguments. We have a simple adjustment 
for arrays, where the array is always unqual'd before IFTI 
define the parameter.


In other words:

const int[] arr;

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

foo(arr) => T = const(int)[], not const(int[])

I think Andrei in the last dconf proposed we do more of this 
with other types (for ranges, specifically). But I think it 
would be good to also define other conversions possibly 
manually.


I agree completely. Like Dennis' code, or that gcd example from 
Phobos, it'd really help to be able to be explicit in the 
signature, not creative in implementation :) Especially 
considering that Unqual is a high-yield type system nuke.




Re: difficulties with const structs and alias this / template functions

2018-11-19 Thread Stanislav Blinov via Digitalmars-d-learn

On Monday, 19 November 2018 at 14:04:29 UTC, Dennis wrote:
On Monday, 19 November 2018 at 13:34:50 UTC, Stanislav Blinov 
wrote:

Because it's not mutation, it's initialization.


Oh. That's an epiphany for me.


:)

When a ctor is `pure`, the compiler knows it doesn't mutate 
any state other than the object's, so it allows conversion to 
all three qualifiers.


I had trouble thinking of an example where impure constructors 
would break immutable, but now I get it:


```
int* gPtr;

struct S {
  int a;
  this(int a) {
this.a = a;
gPtr = 
  }
}

void main() {
  S s = 1;
  (*gPtr)++;
}
```
s can't be immutable because its field could be mutated, so the 
constructor needs to be pure (so gPtr can't be set) or 
immutable (so  is an immutable(int)*).


Yep. Or the other way around (as I said earlier, it really makes 
sense when you have indirections inside the struct):


int* global;

struct S {
 const(int)* a;
 this(bool b) {
 if (b) a = global;
 else a = new int;
 }
}

You obviously can't instantiate an immutable S with that ctor, 
since const(int)* may point to mutable data. Nor can you make 
that ctor `pure`. However this is fine:


immutable(int*) global; // note it's an immutable(int*), not an 
immutable(int)*


struct S {
 const(int)* a;
 this(bool b) pure {
 if (b) a = global;
 else a = new int;
 }
}


Re: difficulties with const structs and alias this / template functions

2018-11-19 Thread Stanislav Blinov via Digitalmars-d-learn

On Monday, 19 November 2018 at 12:28:43 UTC, Dennis wrote:
On Monday, 19 November 2018 at 02:39:32 UTC, Stanislav Blinov 
wrote:

You're skimming the examples ;)


I'm not saying your examples don't work, I'm trying to 
understand the minimum requirements. You said:


"That's [constructors needing to be pure is] only for types 
with indirections (pointers), since `pure` guarantees that you 
do not mutate any global state."


My example was only to show that:
- a const constructor is insufficient for creating an immutable 
struct S
- an immutable or pure constructor is sufficient for creating 
an immutable struct S


Yes, that's what I meant.


You also showed that an inout constructor is sufficient too.

I don't understand why not any constructor would work. After 
all:


"value types are all copyable between mutable/const/immutable. 
So even if `return x + y` would yield a `const T`, you can 
still instantiate a T from it."


Because the rules still hold:

this(int) -> __ctor(T, int);
this(int) const -> __ctor(const T, int);
this(int) immutable -> __ctor(immutable T, int);

Recall that member functions (including constructors) are just 
functions in disguise:

...
what that boils down to, conceptually, is:


I get what inout does know. But continuing on the constructor 
lowering, what strikes me is that:


S __ctor(ref const S this, int x) {
this.x = x; // allowed, while `this` is a const(S)!
// return this; automatically inserted
}

Knowing that a constructor may mutate the const(this) or 
immutable(this) members, why can't a mutable(this) constructor 
be called on an immutable(this), *unless* it is pure (which 
seems irrelevant to me)?


Because it's not mutation, it's initialization. Just like you 
write:


const int x = 1; // initializes a const int
x = 10; // error, can't mutate

...the first assignment to a member in a constructor is 
initialization:


struct S {
int x;
this(int x) immutable {
this.x = x; // ok, initialization
this.x = 5; // error, can't mutate
}
}

When a ctor is `pure`, the compiler knows it doesn't mutate any 
state other than the object's, so it allows conversion to all 
three qualifiers.


What you can do, however, if you don't have an const/immutable 
constructor, is call a mutable constructor explicitly, so long as 
conversion is possible (i.e. value types):


struct S {
this(int) /* not immutable */ {}
}

immutable S x = 1; // error
immutable S x = S(1); // ok


Re: difficulties with const structs and alias this / template functions

2018-11-18 Thread Stanislav Blinov via Digitalmars-d-learn

On Monday, 19 November 2018 at 02:08:14 UTC, Dennis wrote:
On Monday, 19 November 2018 at 01:24:02 UTC, Stanislav Blinov 
wrote:
Yup, that's because, like Rubn said, copying value types is 
trivial. Where it all comes to bite you is when you start 
having pointers, because you can't copy a const(T)* into a T*.


I'm not using reference types, but still:

```
struct S {
int a;
this(int a) {
this.a = a;
}
}

void main()
{
immutable S d = 3;
}

```

onlineapp.d(10): Error: mutable method onlineapp.S.this is not 
callable using a immutable object
onlineapp.d(10):Consider adding const or inout to 
onlineapp.S.this


const still leaves the first error...


You're skimming the examples ;)

struct S {
int a;
this(int a) { this.a = a; }
this(int a) const { this.a = a; }
this(int a) immutable { this.a = a; }
}

or

struct S {
int a;
this(this T)(int a) { this.a = a; }
}


...inout works though I don't know what it does.


Recall that member functions (including constructors) are just 
functions in disguise:


struct S {
this(int a) inout { /* ... */ }
}

what that boils down to, conceptually, is:

void _compiler_made_it_a_struct_S_constructor(ref inout S this, 
int a);


In other words, an `inout` method makes the "this" reference an 
`inout`. Same goes for const, immutable, etc.


Re: difficulties with const structs and alias this / template functions

2018-11-18 Thread Stanislav Blinov via Digitalmars-d-learn

On Monday, 19 November 2018 at 02:03:18 UTC, Dennis wrote:
On Monday, 19 November 2018 at 01:13:29 UTC, Stanislav Blinov 
wrote:

You just dismissed that second to last sentence, did you? :)


I don't know what you mean with it. It's not that I'm trying to 
be sneaky or lazy really trying to modify the const parameter 
when I should treat it properly. And as the author I'm fine 
with Unqualing everything if that's needed, my concern is when 
another person using my type tries to write his own function:


```
q16 pow(q16 base, int exponent) {
  q16 result = 1;
  foreach(i; 0..exponent) result *= base;
  return result;
}

const q16 x = 3;
writeln(pow(x, 3)); //works!
```

He then wants to make it more generic, so he rewrites:

```
Q pow(Q base, int exponent) if (isFixedPoint!Q) {
  Q result = 1;
  foreach(i; 0..exponent) result *= base;
  return result;
}
```

And initially it seems to work, but as soon as it is used with 
const it breaks as `result` can't be mutated anymore.


Yes, but that's not the problem with your type. It's a problem 
with the user not realizing that const is a type qualifier.


I'd like to set the example of writing proper generic 
functions, and if there is something simpler than importing 
Unqual I'd prefer that over my current solution. If there 
isn't, I'll just need to write a "don't forget to Unqual const" 
comment.



```
T f0(T)(inout T x, inout T y) { return x + y; }
```

;)


What does inout do here?


You're right, it's not needed there at all.

If the return type is also inout(T) I know that the return type 
gets the same qualifiers as inout parameters. But in this 
example, the return value is still T.


Because, as before, value types are all copyable between 
mutable/const/immutable. So even if `return x + y` would yield a 
`const T`, you can still instantiate a T from it.




Re: difficulties with const structs and alias this / template functions

2018-11-18 Thread Stanislav Blinov via Digitalmars-d-learn

On Monday, 19 November 2018 at 00:50:28 UTC, Dennis wrote:

I'm also trying to make it work with immutable, and from BigInt 
[2] I learned that constructors need to be `pure` for creating 
immutable objects. (I don't know why.)


That's only for types with indirections (pointers), since `pure` 
guarantees that you do not mutate any global state.


For value types, they work just fine:

struct q16 {
uint x;

this(uint x) { this.x = x; }
this(uint x) const { this.x = x; }
this(uint x) immutable { this.x = x; }

// or again, all three packed together:

this(this T)(uint x) { this.x = x; }
}

Are there any other gotchas? I didn't add an immutable variant 
for toQ32 like Stanislav suggested, but creating an immutable 
q32 from a q16 still seems to work fine.


Yup, that's because, like Rubn said, copying value types is 
trivial. Where it all comes to bite you is when you start having 
pointers, because you can't copy a const(T)* into a T*.




Re: difficulties with const structs and alias this / template functions

2018-11-18 Thread Stanislav Blinov via Digitalmars-d-learn

On Sunday, 18 November 2018 at 20:10:52 UTC, Dennis wrote:
On Sunday, 18 November 2018 at 18:17:54 UTC, Stanislav Blinov 
wrote:


Q log2(Q)(inout Q num) if (is(Q : q16) || is(Q : q32)) { /* 
... */ }


Being able to jam mutable/const/immutable implementation in 
one function like that should tell you that you shouldn't 
mutate the argument. Then, the necessity to Unqual will go 
away on it's own ;)


Different overloads sounds like a lot of boilerplate.
inout still results in "cannot modify `inout` expression 
`input`"


You just dismissed that second to last sentence, did you? :)

My goal is to be able to write straightforward and correct 
signatures for fixed point functions that receive mutable 
copies of whatever they are fed. This isn't even limited to my 
custom types:


```
T f0(T)(T x, T y) {return x += y;}
int  f1(int  x, int  y) {return x += y;}
long f1(long x, long y) {return x += y;}
```
The explicit overloads of f1 work fine, but the generic f0 does 
not.


```
T f0(T)(inout T x, inout T y) { return x + y; }
```

;)

But if you really really want to mutate the argument, then 
handling different mutability for T is the only way:


```
T f0(T)(T x, T y) {
import std.traits : isMutable;
static if (isMutable!T) return x += y;
else return x + y;
}
```

I know it's a bit painful though. In fact, Phobos also suffers 
from it. In std.numeric:


T gcd(T)(T a, T b)
if (isIntegral!T)
{
static if (is(T == const) || is(T == immutable))
{
return gcd!(Unqual!T)(a, b);
}
// ...
}

Not only that looks ugly, but (with DMD) it makes gcd a doulbe 
function call :D


Re: difficulties with const structs and alias this / template functions

2018-11-18 Thread Stanislav Blinov via Digitalmars-d-learn

On Sunday, 18 November 2018 at 17:30:18 UTC, Dennis wrote:
I'm making a fixed point numeric type and want it to work 
correctly with const. First problem:


```
const q16 a = 6;
a /= 2;  // compiles! despite `a` being const.


Ouch. That's actually kind of nasty.


writeln(a);  // still 6
a.toQ32 /= 2;// what's actually happening
```

My q16 type has an implicit conversion to q32 (like how int can 
be converted to long):

```
q32 toQ32() const {
  return q32(...);
}
alias toQ32 this;
```
How do I make it so that a const(q16) will be converted to a 
const(q32) instead of mutable q32?


Like this:

// implement separate methods for mutable/const/immutable
q32 toQ32() {
return q32(x);
}

const(q32) toQ32() const {
return q32(x);
}

immutable(q32) toQ32() immutable {
return q32(x);
}

Or like this:

// implement all three in one method, using the `this 
template` feature

auto toQ32(this T)() {
static if (is(T == immutable))
return immutable(q32)(x);
else static if (is(T == const))
return const(q32)(x);
else
return q32(x);
}



Second problem:
```
Q log2(Q)(Q num) if (is(Q : q16) || is(Q : q32)) {
import std.traits: Unqual;
Unqual!Q x = num;
// actual code
}
```
When I call this with a const(q16), Q is resolved to const(q16) 
so I have to unqualify Q every time. It works, but feels 
clumsy. Is there an easier way to automatically de-const 
parameters? We're working with small value types here, it 
should be simple.


Define different overloads for Q and const Q. Or this:

Q log2(Q)(inout Q num) if (is(Q : q16) || is(Q : q32)) { /* ... 
*/ }


Being able to jam mutable/const/immutable implementation in one 
function like that should tell you that you shouldn't mutate the 
argument. Then, the necessity to Unqual will go away on it's own 
;)


Re: Inconsistency between `AllMembers` and `hasMember`

2018-11-18 Thread Stanislav Blinov via Digitalmars-d-learn

Reported:

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


Re: Inconsistency between `AllMembers` and `hasMember`

2018-11-18 Thread Stanislav Blinov via Digitalmars-d-learn

On Sunday, 18 November 2018 at 09:10:57 UTC, bauss wrote:
On Sunday, 18 November 2018 at 02:37:13 UTC, Stanislav Blinov 
wrote:



It's only "hidden" in that there's no symbol to access it...


But in that case shouldn't you be able to tell whether it has 
it or not through hasMember?


Yah, a case for inconsistency could be made here. IMHO it should 
just have some reserved name like __context.


Re: Inconsistency between `AllMembers` and `hasMember`

2018-11-17 Thread Stanislav Blinov via Digitalmars-d-learn

On Sunday, 18 November 2018 at 00:51:51 UTC, drug wrote:

On 18.11.2018 1:26, Adam D. Ruppe wrote:


That's because the compiler passes it a hidden pointer to 
refer to the context outside. The compiler could perhaps be 
smarter about it, and see if those methods actually refer to 
the context, but it seems to simply say if the method is 
there, it might refer to it and it adds the context pointer 
(note that S.sizeof increases too) and a magic constructor to 
set it.
Well, if "this" means hidden pointer then it never should be 
returned by AllMembers at all, isn't it?


It's only "hidden" in that there's no symbol to access it. But 
you can still access it via .tupleof, and it still of course 
affects the ABI (i.e. S.sizeof is always at least pointer size 
when S is nested).
If you want to iterate fields, .tupleof is a better way to do it. 
As for that hidden pointer, you can just test with 
__traits(isNested, S) whether that's present, and just don't look 
at the last field.


Re: How do you debug @safe @nogc code? Can't figure out how to print.

2018-11-17 Thread Stanislav Blinov via Digitalmars-d-learn

On Saturday, 17 November 2018 at 13:55:24 UTC, aliak wrote:

You can use "debug blah" to hide inside functions that are 
attributed, but when you have an attributed function that calls 
a template, attribtues of which are supposed to be inferred, it 
seems to fail.


Maybe a bug if it's supposed to work?


Indeed that fails, and I would say that's a bug. If it's allowed 
in @nogc, it shouldn't then infer to non-@nogc when not 
explicitly attributed. Maybe debug blocks should outright be 
skipped when inferring?..


Re: How do you debug @safe @nogc code? Can't figure out how to print.

2018-11-17 Thread Stanislav Blinov via Digitalmars-d-learn

On Saturday, 17 November 2018 at 13:13:36 UTC, aliak wrote:


Sawweet! Thanks, that made the printing possible!


You're welcome ;) Still, try a more recent compiler. This works 
fine:


void foo() @nogc {
debug {
import std.stdio;
writefln("%d", 42);
}
}

"scope" is const from what I understand right? It works without 
scope as well. So just "return T".


No, "scope" means "does not escape scope", i.e. you can't assign 
that argument to some global. The only exception is through a 
return, in which case "return" also needed. Whether or not just 
"return" is sufficient, is a bit out there still (AFAIK), between 
DIP25, DIP1000 and current state of the language.
"scope" was implemented for delegates for ages now, exactly to 
allow passing lambdas around without allocating their context on 
the GC heap.


Re: How do you debug @safe @nogc code? Can't figure out how to print.

2018-11-16 Thread Stanislav Blinov via Digitalmars-d-learn

On Friday, 16 November 2018 at 12:59:22 UTC, aliak wrote:

Adding @trusted to declaration of opDispatch gets rid of @safe 
error but I still get "Error: @nogc function D main cannot call 
non-@nogc function". And going through the codebase and 
figuring out where to add @trusted is *very* cumbersome.


I can't figure out how to make this work. The ideal way would 
be just a debug_print() function that works in nogc and safe 
code. I.e. does not affect the attribute inference of templates.


As Zoadian points out, you can now (since 2.079: 
https://dlang.org/changelog/2.079.0.html#bugfix-list) shamelessly 
call @nogc inside debug blocks.


To get at where the problematic areas were in the code in 
question though, it's as follows:



auto assumeNoGC(T)(T t) {  // point 1
import std.traits;
enum attrs = functionAttributes!T | FunctionAttribute.nogc;
// point 2:
return cast(SetFunctionAttributes!(T, functionLinkage!T, 
attrs)) t;

}


At 'point 1', you just take by value. If `t` ends up being a 
closure, D will allocate. That's where it breaks the @nogc. 
Solution:


auto assumeNoGC(T)(return scope T t) { /* ... */ }

Now you take (and return) a `scope` t, in that case when `t` is a 
closure D won't allocate it on the GC heap.


At 'point 2' you make an un-@safe cast, that's where it breaks 
@safe. Given that the whole deal is just a debugging hack, you 
could mark the whole function @trusted:


auto assumeNoGC(T)(return scope T t) @trusted { /* ... */ }


Re: Sorting a subrange

2018-11-16 Thread Stanislav Blinov via Digitalmars-d-learn

On Friday, 16 November 2018 at 11:24:20 UTC, Per Nordlöw wrote:


/** Sort sub-range [sub_begin, sub_end] of [begin, end].
 *
 * Describe at 
https://www.youtube.com/watch?v=0WlJEz2wb8Y=2686s

 */
template// I models RandomAccessIterator
void sort_subrange(I begin, I end,
   I sub_begin, I sub_end)
{
if (sub_begin == sub_end) { return; }
if (sub_begin != begin)
{
std::nth_element(begin, sub_begin, end);
++sub_begin;
}
std::partial_sort(sub_begin, sub_begin, end);
}


Back-of-the-envelope translation (probably some error checking 
would be in order):


import std.range.primitives : isRandomAccessRange;

auto sortSubRange(R)(R range, size_t i, size_t j) if 
(isRandomAccessRange!R) {

import std.algorithm.sorting : topN, partialSort;
size_t start = i;
if (i != 0) {
topN(range, i);
start++;
}
partialSort(range[start .. $], j-start);
return range[i .. j];
}

void main() {
auto x = [1,2,7,4,2,6,8,3,9,3];
auto y = sortSubRange(x, 3, 6);
import std.stdio;
writeln(y); // 3, 3, 4
writeln(x); // ex. 2, 2, 1, 3, 3, 4, 6, 7, 9, 8
}



Re: Inherit from class based on bool value

2018-11-13 Thread Stanislav Blinov via Digitalmars-d-learn

On Tuesday, 13 November 2018 at 07:10:26 UTC, Jamie wrote:

Is this possible? I can't get it to work in the way I'm showing 
above.


...or abstract away Ali's solution:

enum OPTION {
FALSE,
TRUE,
}

template Select(OPTION opt, IfTrue, IfFalse) {
static if (opt == OPTION.TRUE) alias Select = IfTrue;
else alias Select = IfFalse;
}

class One {}
class Two {}

class Top(OPTION opt) : Select!(opt, One, Two) {}

void main() {
import std.traits : BaseClassesTuple;
auto t1 = new Top!(OPTION.TRUE);
static assert(is(BaseClassesTuple!(typeof(t1))[0] == One));
auto t2 = new Top!(OPTION.FALSE);
static assert(is(BaseClassesTuple!(typeof(t2))[0] == Two));
}



Re: dip1000: why can't the addressee come into existence later?

2018-11-10 Thread Stanislav Blinov via Digitalmars-d-learn
On Saturday, 10 November 2018 at 06:56:29 UTC, Neia Neutuladh 
wrote:

The following code doesn't work with @safe -dip1000:

int* p;
int i;
p = 

i has a shorter lifetime than p, the compiler complains.

But this code does:

int i;
int* p;
p = 

The compiler does this even in the absence of scope guards and 
destructors because simple, obvious rules will be easier to 
understand and implement than nuanced ones, even if it makes 
you reorder declarations sometimes.


Is this right?


Yep, you just over-simplified the first case. Consider:

int* p;
{
int i;
p = 
}
*p = 42;

or even:

module thing;

int* global;

void foo() {
int i;
global = 
}

...much simpler to just go by the lifetime, instead of attempting 
to do a complex analysis. Because for the latter, it would then 
*need* to be deep to be of any use at all. Especially in a 
language that has static ifs:


// parameter is not scope, function is not pure, etc.
void nasty(int* p) { /* ... */ }

void main() {
int *p;
int i;
p = 
static if (someCondition) nasty(p);
}



Re: Exception slipping through the catch block?

2018-11-08 Thread Stanislav Blinov via Digitalmars-d-learn

On Thursday, 8 November 2018 at 16:13:55 UTC, Mike Parker wrote:

On Thursday, 8 November 2018 at 15:50:38 UTC, helxi wrote:


Although it's pretty frustrating, isn't it? Now not only I 
have to think about catching exceptions but also about Errors, 
and have no guarantee that I have everything under control.


No, you should never catch Errors. They're separate for a 
reason.


Never say never :) There are legitimate cases for catching an 
Error or even a Throwable (for example, error propagation in a 
multi-threaded environment). However, this is not one of such 
cases.


helxi, an AssertError means there's a problem with your code, it 
needs to be dealt with by fixing the code, not swallowing the 
Error.


Re: Is this a bug? +goto

2018-11-07 Thread Stanislav Blinov via Digitalmars-d-learn
On Wednesday, 7 November 2018 at 20:03:47 UTC, Michelle Long 
wrote:



Case A:

int x;
{
   if (true) goto X;
   //int x;
}
~x;
X:


That is not "Case A". This one is:

{
if (true) goto X;
T x;

X:
} // x.__dtor

That should error as an easy cop-out, nothing wrong with that 
approach. However, this:


{
if (true) goto X;
T x;
} // x.__dtor
X:

should not error at all, since goto skips both initialization and 
use. No one is disputing that. From your posts if I understand 
correctly it's that second case that errors in your code. If it 
does, there's a bug, but it's on you to provide a test case. 
Simple as that. Yet you're all wound up as if the world is out to 
get you.


Re: Module function conflicting with reserve function

2018-11-06 Thread Stanislav Blinov via Digitalmars-d-learn

On Tuesday, 6 November 2018 at 21:19:29 UTC, Peter Campbell wrote:

Given your second example that makes me think that, because 
object functions are provided by the runtime without me 
explicitly importing it, this is likely only an issue for 
object functions? Or can this behaviour happen with any free 
functions with the same name but completely different parameter 
types?


Not with completely different parameter types, no. But it can 
happen with functions imported from different modules, as they're 
from different overload sets. There's an example in that Overload 
Sets section of the spec.


Re: Module function conflicting with reserve function

2018-11-06 Thread Stanislav Blinov via Digitalmars-d-learn
Sorry, forgot to put the spec link into my previous resonse: 
https://dlang.org/spec/function.html#overload-sets


Re: Module function conflicting with reserve function

2018-11-06 Thread Stanislav Blinov via Digitalmars-d-learn

On Tuesday, 6 November 2018 at 20:40:11 UTC, Peter Campbell wrote:
Hi there. I've been playing with D and have encountered this 
really awkward behaviour. Basically I'm getting a compiler 
error inside a function I wrote in my module as it thinks I'm 
trying to call itself with invalid parameters, when actually I 
want it to call the reserve function on the array itself. Is 
this a bug or expected behaviour? It seems quite strange and 
potentially annoying to me.


It's not a bug, just the way name resolution works. Better have 
collision than silent overloads. Possible solutions:


```
void reserve(ref Bob system, in size_t capacity) {
 // explicitly disambiguate
 object.reserve(system._data, capacity);
}
```

or:

// pull in the runtime 'reserve' into this module's scope
alias reserve = object.reserve;

void reserve(ref Bob system, in size_t capacity) {
 // call reserve as usual
 system._data.reserve(capacity);
}


Re: Is this a bug? +goto

2018-11-05 Thread Stanislav Blinov via Digitalmars-d-learn

On Tuesday, 6 November 2018 at 00:38:01 UTC, MatheusBN wrote:
On Tuesday, 6 November 2018 at 00:13:52 UTC, Stanislav Blinov 
wrote:

But here it's fine:

void main(){
 {
 goto Q;
 S x;
 } // <---
 Q:
 writeln("a");
}

because goto jumps over both initialization *and* destruction, 
i.e. neither would even be performed.


I see but at same time I found a bit confusing, because in this 
case we're just adding a new scope to fix the issue, and like I 
said to Jonathan, I thought that "x" wouldn't be initialized 
since it is never used.


It's not as simple as that, that's why I specifically showed the 
destructor case. Even if you don't see any explicit use, it 
doesn't mean the compiler doesn't see an implicit one.






Re: Is this a bug? +goto

2018-11-05 Thread Stanislav Blinov via Digitalmars-d-learn

On Monday, 5 November 2018 at 23:54:59 UTC, MatheusBN wrote:

Hi,

I posted this in another thread but without any response.

This code:

void main(){
 goto Q;
 int x;
 Q:
 writeln("a");
}

Gives me this error: "source_file.d(4): Error: goto skips 
declaration of variable source.main.x at source_file.d(5)"



Now, if I add a pair of brackets:

void main(){
 {
 goto Q;
 int x;
 }
 Q:
 writeln("a");
}

It works. So Is this a bug?



No, it's not. Consider replacing that int with a type that has a 
destructor:


struct S { ~this() { /* ... */ } }

void main(){
 goto Q;
 S x;
 Q:
 writeln("a");
} // <---

Now, what should happen at that closing paren is a destructor 
call, x.__dtor. However, goto jumps over initialization of 'x', 
which would lead to calling a destructor on an uninitialized 
value. That's why the compiler disallows such skips.


But here it's fine:

void main(){
 {
 goto Q;
 S x;
 } // <---
 Q:
 writeln("a");
}

because goto jumps over both initialization *and* destruction, 
i.e. neither would even be performed.


I'm guessing you misunderstood the author of that other thread. 
What he's saying is that code similar to the *second* version 
fails. That's what all the commotion is about over there. This 
simple example obviously works, yet in his more complicated code 
base something goes wrong.


Re: Implicit cast to const of result returned from findSplit()

2018-11-05 Thread Stanislav Blinov via Digitalmars-d-learn

On Monday, 5 November 2018 at 13:26:18 UTC, Per Nordlöw wrote:

AFAICT, it looks like a missing bool qualifier on 
`opCast!bool`, right?


...Like a missing 'const' qualifier ;)

auto findSplit(alias pred = "a == b", R1, R2)(R1 haystack, R2 
needle)

// ...
static struct Result(S1, S2) if (isForwardRange!S1 &&
 isForwardRange!S2)
{
// ...
bool opCast(T : bool)()
{
return !asTuple[1].empty;
}
// ...
}



Re: d word counting approach performs well but has higher mem usage

2018-11-03 Thread Stanislav Blinov via Digitalmars-d-learn

On Saturday, 3 November 2018 at 14:26:02 UTC, dwdv wrote:


Assoc array allocations?


Yup. AAs do keep their memory around (supposedly for reuse). You 
can insert calls to GC.stats (import core.memory) at various 
points to see actual GC heap usage. If you don't touch that AA at 
all you'll only use up some Kb of the GC heap when reading the 
file.

Why it consumes so much is a question to the implementation.


What did I do wrong?


Well, you didn't actually put the keys into the AA ;) I'm 
guessing you didn't look closely at the output, otherwise you 
would've noticed that something was wrong.


AAs want immutable keys. .byLine returns (in this case) a char[]. 
It's a slice of it's internal buffer that is reused on reading 
each line; it gets overwritten on every iteration. This way the 
reading loop only consumes as much as the longest line requires. 
But a `char[]` is not a `string` and you wouldn't be able to 
index the AA with it:


```
Error: associative arrays can only be assigned values with 
immutable keys, not char[]

```

But by putting `const` in `foreach` you tricked the compiler into 
letting you index the AA with a (supposed) const key. Which, of 
course, went fine as far as insertion/updates went, since hashes 
still matched. But when you iterate later, pretty much every key 
is in fact a reference to some older memory, which is still 
somewhere on the GC heap; you don't get a segfault, but neither 
do you get correct "words".


You *need* to have an actual `string` when you first insert into 
the AA.


```d 
===

void main()
{
import std.stdio, std.algorithm, std.range;

  import core.memory;


int[string] count;


  void updateCount(char[] word) {
  auto ptr = word in count;
  if (!ptr)
  // note the .idup!
  count[word.idup] = 1;
  else
  (*ptr)++;
  }

  // no const!

foreach(word; stdin.byLine.map!splitter.joiner) {

  updateCount(word);

}

//or even:
//foreach(line; stdin.byLine) {

// no const!

//foreach(word; line.splitter) {

  //updateCount(word);

//}
//}


  writeln(GC.stats);
  GC.collect;
  writeln(GC.stats);


count.byKeyValue
.array
.sort!((a, b) => a.value > b.value)
.each!(a => writefln("%d %s", a.value, a.key));


  writeln(GC.stats);
  GC.collect;
  writeln(GC.stats);

}
```


Note that if you .clear() and even .destroy() the AA, it'll still 
keep a bunch of memory allocated. I guess built-in AAs just love 
to hoard.


Re: Full precision double to string conversion

2018-11-03 Thread Stanislav Blinov via Digitalmars-d-learn
On Saturday, 3 November 2018 at 17:26:19 UTC, Ecstatic Coder 
wrote:



void main() {
double value = -12.000123456;
int precision = 50;

import std.stdio;
writefln("%.*g", precision, value);

import std.format;
string str = format("%.*g", precision, value);
writeln(str);
}

Prints:

-12.00012345600743415512260980904102325439453125
-12.00012345600743415512260980904102325439453125

That's not quite the -12.000123456 that you'd get from C#'s 
ToString().


Unfortunately, but that's still better though, thanks :)


I don't think you understood what I meant. Neither C# nor D 
attempt to exhaust the precision when converting, given default 
arguments. It's merely a matter of those defaults. The snippet 
above obviously provides *more* digits that the default 
.ToString() in C# would.


But indeed what I really need is a D function which gives a 
better decimal approximation to the provided double constant, 
exactly in the same way those in Dart and C# do.


Is there really no such function in D ?


When you call .ToString() in C# with no arguments, it assumes the 
"G" format specifier.


https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings?view=netframework-4.7.2#the-general-g-format-specifier

So for a double, it will use 15-digit precision. D's to!string 
simply uses lower default. If you want the exact same behavior as 
in C#, you can do this:


string toStringLikeInCSharp(double value) {
import std.format : format;
return format("%.15G", value);
}

void main() {
double value = -12.000123456;
import std.stdio;
writeln(value.toStringLikeInCSharp); // prints: -12.000123456
}


Re: Full precision double to string conversion

2018-11-03 Thread Stanislav Blinov via Digitalmars-d-learn
On Saturday, 3 November 2018 at 13:20:22 UTC, Ecstatic Coder 
wrote:
On Saturday, 3 November 2018 at 12:45:03 UTC, Danny Arends 
wrote:


How can I convert a double value -12.000123456 to its string 
value "-12.000123456", i.e. without loosing double-precision 
digits ?


Specify how many digits you want with writefln:

writefln("%.8f", value);


Actually, what I need is the D equivalent of the default 
ToString() function we have in Dart and C#.


I don't think it means what you think it means:

void main() {
double value = -12.000123456;
int precision = 50;

import std.stdio;
writefln("%.*g", precision, value);

import std.format;
string str = format("%.*g", precision, value);
writeln(str);
}

Prints:

-12.00012345600743415512260980904102325439453125
-12.00012345600743415512260980904102325439453125

That's not quite the -12.000123456 that you'd get from C#'s 
ToString().


I mean a dumb double-to-string standard library conversion 
function which returns a string including all the double 
precision digits stored in the 52 significant bits of the 
value, preferably with the trailing zeroes removed.


All of them? Most implementations of conversion algorithms 
actually stop when it's "good enough". AFAIR, D doesn't even have 
it's own implementation and forwards to C, unless that changed in 
recent years.


Re: Dealing with raw types as attributes

2018-11-01 Thread Stanislav Blinov via Digitalmars-d-learn
On Thursday, 1 November 2018 at 20:33:10 UTC, Neia Neutuladh 
wrote:

On Thu, 01 Nov 2018 20:01:51 +, Stanislav Blinov wrote:

Check if an UDA is a type?.. As in, not just `is(uda == Foo)`,
but simply `is(uda)`:


Which works, but generally makes things more complex in code 
that's already pretty deeply nested. It's also something I have 
to worry about every time I do the static foreach to get UDAs, 
in the cases where that's more than once.


Yes, it does :(

 I could use a customized version of [getUDAs] that replaces 
@Type with @Type.init, and that's a reasonable choice...


That can't be generic, as you can have UDAs that don't have an 
.init:


enum XXX;

@XXX int bar;

static foreach (uda; __traits(getAttributes, bar)) {
static if (is(uda == XXX)) {
pragma(msg, "bar is XXX");
}
}

...but so long as you can live without such UDAs, I guess it 
could work.


Re: Dealing with raw types as attributes

2018-11-01 Thread Stanislav Blinov via Digitalmars-d-learn
On Thursday, 1 November 2018 at 16:14:45 UTC, Neia Neutuladh 
wrote:
The spec says that a user-defined attribute must be an 
expression, but DMD accepts a wide range of things as UDAs:


  struct Foo { string name = "unknown"; }
  @Foo int bar;

`bar` has the *type* Foo as an attribute. It's not an 
*instance* of Foo. So if I try to look at the UDAs:


  static foreach (uda; __traits(getAttributes, bar))
  {
static if (is(typeof(uda) == Foo))
{
  pragma(msg, "bar is @Foo");
}
  }

That just doesn't work; typeof(Foo) isn't anything, so 
is(typeof(Foo) == Foo) is false.


I can change my code to read `static if (is(uda == Foo))`. But 
that obviously fails:


  @Foo("customName") int bar2;

What do you do to handle this?


Check if an UDA is a type?.. As in, not just `is(uda == Foo)`, 
but simply `is(uda)`:


```
struct Foo { string name = "unknown"; }
@Foo @string @Foo("hello") int bar;

static foreach (uda; __traits(getAttributes, bar)) {
static if (is(uda)) {
// if `uda` is a type...
static if (is(uda == Foo)) {
pragma(msg, "bar is @Foo!!!");
} else {
pragma(msg, "bar is "~uda.stringof);
}
} else {
// if `uda` is not a type...
pragma(msg, "bar is "~uda.stringof);
}
}
```


Re: expanding variadic into format

2018-10-31 Thread Stanislav Blinov via Digitalmars-d-learn

On Wednesday, 31 October 2018 at 12:13:57 UTC, Codifies wrote:
On Wednesday, 31 October 2018 at 12:09:04 UTC, Stanislav Blinov 
wrote:



```
void printValue(Args...)(Font fnt, float x, float y, string 
frmt, auto ref Args args) {

// ...
import std.functional : forward;
string message = format(frmt, forward!args);
// ...
}
```


thats fantastic thanks so much, can you explain a little more 
about whats going on here ?


As rikki already explained, std.format is a variadic template, 
which gets expanded into argument list at compile time. That's 
why it can't be used with C-syle variadics: when you passed 
_arguments, the expansion treated that as a single argument 
instead of a tuple.
Therefore, to forward arguments to std.format, your `printValue` 
must also be a variadic.


There are, broadly speaking, two ways to pass arguments to 
functions: by value and by reference.


When you make a template like this:

void foo(T)(T value) { /* ... */ }

it will take the argument by value, making copies when necessary:

struct S { /* ... */ }

S s;
foo(S.init); // calls foo without copying, argument is 
constructed directly

foo(s); // copies `s` and passes that copy to `foo`

If that template is defined like this:

void foo(T)(ref T value) { /* ... */ }

then it will *only* take argument by reference:

foo(S.init); // error, 'ref' cannot bind to rvalue
foo(s); // no copy is made, `foo` takes `s` by reference

There are more subtleties, especially when taking `const ref` 
arguments, but I won't get into those.


There's a special syntax for template functions: `auto ref` 
arguments. Those are deduced to be by-value or by-reference at 
compile time (see

https://dlang.org/spec/template.html#auto-ref-parameters):

void foo(T)(auto ref T value) { /* ... */ }

foo(S.init); // works, compiles as foo(S);
foo(s); // works, compiles as foo(ref S);

But, because inside of function definition all arguments are 
lvalues, you lose this additional information if you pass them to 
another function directly. To preserve that information, there's 
a `forward` template in std.functional. D doesn't have rvalue 
references, so that template will still copy the bits of 
non-`ref` arguments, but it will not call postblits, etc (it 
`move`s them using std.algorithm.mutation.move).


So, there are two possible ways to implement your print:

// Take all Args by value, i.e. copy everything first time
void printValue(Args...)(Font fnt, float x, float y, string frmt, 
Args args) {
// make copies of every argument in `args` (again) and pass 
those to `format`

auto message = format(frmt, args);
}

or

// Infer whether each argument is an lvalue or not
void printValue(Args...)(Font fnt, float x, float y, string frmt, 
auto ref Args args) {

import std.functional : forward;
// preserve lvalue/rvalue
string message = format(frmt, forward!args);
}

Both allow you to accomplish your goal, but the second one only 
copies the argument bits when necessary.


Getting into finer implementation nuances, conceptually this 
allows a function to even take and pass around non-copyable types 
as arguments. Sadly, this is not widely adopted by Phobos, which 
likes to make unnecessary copies. I.e. the `format` function 
itself takes Args by value, even though it probably should take 
advantage of this specific language feature. But at least calling 
it via `forward`, you only make necessary copies once, instead of 
twice.




Re: expanding variadic into format

2018-10-31 Thread Stanislav Blinov via Digitalmars-d-learn

On Wednesday, 31 October 2018 at 11:53:52 UTC, Codifies wrote:


void printValue(Font fnt,float x, float y, string frmt, ...)
{
/* matrix math and other stuff removed for readability */
string message = format(frmt, _arguments);




is there some way to somehow transfer my input variadic into 
formats variadic ?



Just to confirm, format there is std.format:format right?
Because that isn't using C variadics, its using template 
variadics.


...as in:

```
void printValue(Args...)(Font fnt, float x, float y, string frmt, 
auto ref Args args) {

// ...
import std.functional : forward;
string message = format(frmt, forward!args);
// ...
}
```


Re: struggling to link against a C global in D (win/vs2017)

2018-10-28 Thread Stanislav Blinov via Digitalmars-d-learn

On Monday, 29 October 2018 at 00:01:21 UTC, DanielG wrote:


In my D app I'm declaring it this way:

extern (C) {
extern __gshared int myIntValue;
int myIntFunc (int a, int b);
}

The function seems to link OK, but the C global will not.


Should it be extern(Windows), perchance?.. (I haven't D on 
Windows for ages).




Re: how to make '==' safe for classes?

2018-10-28 Thread Stanislav Blinov via Digitalmars-d-learn

On Sunday, 28 October 2018 at 12:38:12 UTC, ikod wrote:

and object.opEquals(a,b) do not inherits safety from class C 
properties, and also I can't override it.


Yep. Since Object is the base class and it defines opEquals as:
```
bool opEquals(Object);
```

the compiler rewrites `a == b` as 
`(cast(Object)a).opEquals(cast(Object)ob)`, i.e. it inserts a 
@system call into your code.


Is there clean way to use '==' here, or I have to convert this 
to a.opEquals(b) for classes, leaving '==' for structs?


Pretty much, yes. "Implicit" value comparison in general is 
somewhat alien for classes, since they're reference types.


Re: Built-in array opSliceAssign

2018-10-25 Thread Stanislav Blinov via Digitalmars-d-learn
On Thursday, 25 October 2018 at 13:22:36 UTC, Eduard Staniloiu 
wrote:


The spec doesn't exactly say it uses memset, but it does imply 
it:


https://dlang.org/spec/arrays.html#array-copying

talking about "aggressive parallel code optimizations than 
possible with the serial semantics of C" and "copying" rather 
than "assigned" etc.


but indeed postblit lets this work.


You are right. Thank you!

I guess I never read/understood it like this.
I expected it to use opAssign as that is what's the most 
natural and intuitive decision for me.


I take it that this is the expected behaviour, then.


I don't think interpreting the spec like that is correct. It says 
"...it means that the *contents* of the array are the target of 
the *assignment*...", and further, in the examples:


s[1..2] = t[0..1]; // same as s[1] = t[0]
s[0..2] = t[1..3]; // same as s[0] = t[1], s[1] = t[2]

The current behavior of the compiler is quite the opposite of 
those "same as" above.


Consider:

struct S {
@disable this(this); // can't implicitly copy, i.e. pass 
lvalue to a function
void opAssign(ref S rhs) { /* ... */ } // but can explicitly 
copy

}

void main() {
S x, y;
x = y; // works
S[10] a;
a[0 .. 3] = y; // doesn't compile, i.e. NOT "same as 
a[0] = y, a[1] = y, a[2] = y"
a[0 .. 3] = a[3 .. 6]; // doesn't compile either, i.e. NOT 
"same as a[0] = a[3], a[1] = a[4], a[2] = a[5]"

}

I've filed an issue about this around a month ago: 
https://issues.dlang.org/show_bug.cgi?id=19274


Re: need help about get all public static function name

2018-10-22 Thread Stanislav Blinov via Digitalmars-d-learn

On Monday, 22 October 2018 at 12:03:22 UTC, test wrote:

On Monday, 22 October 2018 at 11:59:21 UTC, test wrote:

On Monday, 22 October 2018 at 11:42:59 UTC, test wrote:
I try made a simple example but it has no error:



I find the way to show the error:

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


import std.traits;

struct FiberS {
static auto getThis(){
return Fiber.getId();
}
}

struct Proxy(T){
T* ptr;
alias getPayload this;

@property ref auto getPayload() inout return {
return * ptr ;
}

static auto getId(){
return 1;
}
}
alias Fiber = Proxy!(FiberS);


extern(C) void main(){
   auto id = Fiber.getThis(); // work here
}

struct TcpStream {
void read(ubyte[] data){
   auto id = Fiber.getThis(); // not work here in my 
case

}
}


Let's analyze this call:

auto id = Fiber.getThis();

You're trying to call a static function 'getThis' on Fiber.
The type 'Fiber' is really a Proxy!FiberS. Proxy doesn't have a 
static getThis() function. So the compiler tries an 'alias this', 
which forwards to a non-static member function getPayload(). To 
call that function, you need an instance of 'Proxy', which you 
don't have.
I guess the first error message ("this for getPayload needs to be 
type Proxy not type TcpStream") just doesn't report that clearly.


  1   2   3   >