Re: Renamed but non-selective import?

2021-01-12 Thread ag0aep6g via Digitalmars-d-learn

On 12.01.21 21:09, cc wrote:

import core.sys.windows.windows;
import mymodule; // contains a struct named MSG
Error: `core.sys.windows.winuser.MSG` ... conflicts with `mymodule.MSG`

vs

import core.sys.windows.windows : winMSG = MSG; // this leaves out other 
symbols

Error: undefined identifier `HWND`
Error: undefined identifier `LPCSTR`


import core.sys.windows.windows;
import mymodule;
alias MSG = mymodule.MSG;
alias winMSG = core.sys.windows.windows.MSG;


Re: Easy way to accept X and immutable X in parameters without overloading?

2021-01-11 Thread ag0aep6g via Digitalmars-d-learn

On Monday, 11 January 2021 at 18:51:04 UTC, Jack wrote:

Here's what I'm trying to make to work:

import std.container : SList;

class C
{
static immutable Foo = new C();
   // 
}

alias Callback = void function(const C, int);

void main()
{
auto l = SList!Callback();
auto a = (C c, int d) { };
auto b = (C c, int d) { };
auto c = (const C c, int d) { };
l.insert(a);
l.insert(b);
l.insert(c);
}


I'm assuming that you then want to call the callbacks on mutable 
and immutable `C`s like `C.Foo`.


You have to add `const` to the `a` and `b` functions, too:

auto a = (const C c, int d) { };
auto b = (const C c, int d) { };

Without those `const`s, you have callbacks with mutable 
parameters being called on an immutable object. That cannot work.


Re: Easy way to accept X and immutable X in parameters without overloading?

2021-01-11 Thread ag0aep6g via Digitalmars-d-learn

On Monday, 11 January 2021 at 18:12:17 UTC, Jack wrote:

thanks! now, how would I add const here?

import std.container : SList;
auto l = SList!Callabck();

doesn't work:

auto l = SList!(const(Callabck()));
auto l = SList!(const Callabck());


You said you want the callbacks to accept both mutable and 
immutable. So make the parameter `const` in the callback type:


alias Callabck = void function(const X foo);

If you wanted an `SList` of `const Callabck`s, you'd write that 
like so:


auto l = SList!(const Callabck)();

But it seems like `SList` doesn't support const elements. And I 
don't think that's what you actually want anyways.


(By the way, you've got a typo there in "Callabck".)


Re: Easy way to accept X and immutable X in parameters without overloading?

2021-01-11 Thread ag0aep6g via Digitalmars-d-learn

On Monday, 11 January 2021 at 16:40:01 UTC, Jack wrote:

let's say a I have this:

void f(X foo) { }

but I'd like to make f() accept immutable X too so instead of 
cast away everywhere in the code where immutable(X) is passed 
to f() or make a overload for this, are there any way to accept 
both in same function? those function are callback-like 
functions, I have lots of them so already and would need to 
double, if I do add an overload just for the immutable. I did 
come up with something using templates, not sure if it's ugly:


void f(T)(T x)
if(is(T == C) || is(T == immutable(C)) {
// ...
}


Accepting both mutable and immutable is what `const` is for:

void f(const X foo) { ... }


Re: Surprising behaviour of std.experimental.allocator

2020-12-26 Thread ag0aep6g via Digitalmars-d-learn

On 26.12.20 13:59, ag0aep6g wrote:
Looks like a pretty nasty bug somewhere in std.experimental.allocator or 
(less likely) the GC. Further reduced code:




[...]



Apparently, something calls deallocateAll on a Mallocator instance after 
the memory of that instance has been recycled by the GC. Maybe 
allocatorObject or AllocatorList keep a reference to GC memory out of 
sight of the GC.


I've looked into it some more, and as far as I can tell this is what 
happens:


1) allocatorObject puts the AllocatorList instance into malloced memory.
2) The AllocatorList puts the Mallocator instance into GC memory, 
because its default BookkeepingAllocator is GCAllocator.
3) The GC recycles the memory of the Mallocator instance, because it's 
only reachable via the malloced AllocatorList instance and malloced 
memory isn't scanned by default.

4) Hell breaks loose because that recycled memory was not actually garbage.

I'm not so sure anymore if this qualifies as a bug in 
std.experimental.allocator. Maybe AllocatorList should be registering 
its GC allocations as roots?


As a solution/workaround, you can use NullAllocator for AllocatorList's 
BookkeepingAllocator:



import std.experimental.allocator.building_blocks.null_allocator :
NullAllocator;
alias Alloc1 = FallbackAllocator!(
AllocatorList!(n => Region!Mallocator(1024*1024), NullAllocator),
Mallocator);



Re: Surprising behaviour of std.experimental.allocator

2020-12-26 Thread ag0aep6g via Digitalmars-d-learn

On 24.12.20 17:12, Saurabh Das wrote:

This causes a segfault when run with rdmd -gx:


[...]


(Tested on DMD 2.094.2 and on https://run.dlang.io/is/p0FsOQ)

If the "GC.collect()" line is commented out, it works somehow.

Please help me understand why this is happening. This is a very reduced 
example of an issue I am facing.


Looks like a pretty nasty bug somewhere in std.experimental.allocator or 
(less likely) the GC. Further reduced code:



import core.memory: GC;
import core.stdc.stdlib: malloc;
import std.experimental.allocator: allocatorObject;
import std.experimental.allocator.building_blocks.allocator_list: 
AllocatorList;

import std.stdio: writeln;
import std.typecons: Ternary;

struct Mallocator
{
int x = 42;
void[] allocate(size_t n) nothrow @nogc
{
assert(n == 56); /* memory for bookkeeping, presumably */
void* p = malloc(n);
assert(p !is null);
debug writeln(, " malloced ", p);
return p[0 .. n];
}
Ternary owns(const void[] a) pure nothrow @nogc @safe
{
debug writeln(, " owns?", a.ptr);
return a.ptr is null ? Ternary.no : Ternary.yes;
}
bool deallocateAll() pure nothrow @nogc @safe
{
assert(x == 42); /* fails; should pass */
return true;
}
enum alignment = 1;
}

struct List
{
AllocatorList!(n => Mallocator()) list;
void[] allocate(size_t n) nothrow
{
return list.allocate(n);
}
bool deallocate(void[] a) pure nothrow @nogc @safe { return false; }
enum alignment = 1;
}

void main()
{
auto alloc1 = allocatorObject(List());
() { ubyte[1000] stomp; } ();
GC.collect();
auto gca = new int;
}


Apparently, something calls deallocateAll on a Mallocator instance after 
the memory of that instance has been recycled by the GC. Maybe 
allocatorObject or AllocatorList keep a reference to GC memory out of 
sight of the GC.


Re: Why is (int[int] s = int[int].init) not allowed

2020-12-22 Thread ag0aep6g via Digitalmars-d-learn

On Tuesday, 22 December 2020 at 21:11:12 UTC, Andre Pany wrote:

I am really confused, why is this valid:
void sample(string[string] s = string[string].init){}

while this causes syntax errors?

void sample_invalid1(double[string] s = double[string].init){}
void sample_invalid2(int[int] s = int[int].init){}


Looks like an oddity in the grammar.

`string` is an alias, meaning it's an identifier. And an 
identifier is a valid expression to the grammar. So 
`string[string]` is parsed as an IndexExpression. Only during 
semantic analysis does the compiler figure out that it's actually 
a type.


`double` and `int` aren't identifiers. They're keywords. And 
they're always types, never expressions. So `int[int]` cannot be 
parsed as an IndexExpression. It's parsed as a Type instead. And 
for a (grammatical) Type, there is no rule that allows 
`Type.Identifier`.


You can work around with parentheses:

(double[string]).init;
(int[int]).init


Re: Trying to understand multidimensional arrays in D

2020-12-22 Thread ag0aep6g via Digitalmars-d-learn

On Tuesday, 22 December 2020 at 16:56:18 UTC, Ali Çehreli wrote:

On 12/22/20 6:35 AM, ag0aep6g wrote:

> Flip the pointer syntax, too:
>
>  *Foo a; /* a pointer to a Foo */

I am not a language expert but I think that would make D's 
parsing complicated (like C++'s < token) because * already 
means "derefence" in that position. So, the parser would see 
*Foo as a potential compilation error but would have to parse 
forward, etc.


I'm not seriously suggesting changing D's syntax. The current 
syntax is fine with me.


`Foo* a;` is already "complicated", though. `*` can also mean 
multiplication in that position:



struct F
{
F opBinary(string op : "*")(F a) { return F(); }
void opBinary(string op : "+")(int a) { import std.stdio; 
writeln("Hello, world!"); }

}
void main()
{
F Foo;
F a;
Foo* a + 1; /* prints "Hello, world!" */
}


That's a convoluted example, of course. But it shows that the 
compiler already has to look ahead to decide what the `*` means. 
It doesn't just go "That's a type!" when it sees "Foo*".


Re: Trying to understand multidimensional arrays in D

2020-12-22 Thread ag0aep6g via Digitalmars-d-learn

On 22.12.20 15:15, Mike Parker wrote:

On Tuesday, 22 December 2020 at 13:59:54 UTC, Rekel wrote:



I am curious by the way, what do you think of the [][4]Row suggestion 
I gave? In a way you'd have your  & could eat it too, i think ^^

(Still a strange saying to me)


Currently, D's variable declaration syntax is consistent and, IMO, make 
sense:


Type Name | Extra Tokens | SymbolName
Foo   *   a;
Foo   [4] b;
(Foo  [4])[]  c;

[][4]Foo is completely backwards from and inconsistent with the pointer 
declaration syntax. We shouldn't want to intentionally introduce 
inconsistencies.


Flip the pointer syntax, too:

*Foo a; /* a pointer to a Foo */
  [4]Foo b; /* an array of four Foos */
[][4]Foo c; /* a dynamic array of arrays of four Foos each */

But now we're no longer C-like, I guess.


Re: Undefined reference error at linktime with unittests

2020-12-10 Thread ag0aep6g via Digitalmars-d-learn

On 10.12.20 13:28, z wrote:
When compiling with unit tests(via «dub test», or adding «dflags 
"-unittest"»), i'm getting this error at link time :


lld-link: error: undefined symbol: 
_D5packagename9subpackage9__mixin119type8toStringMFZAya

The same occurs with OPTLINK.

Curiously, looking at the incriminated .lib file with an hexadecimal 
editor reveals something odd:

_D5packagename9subpackage9__mixin109type8toStringMFZAya
(the mangled name in the .lib is mixin109, but the linker is 
complaining that it cannot find a "mixin119" version of the symbol.)


Is there something i am doing wrong? I couldn't find documentation on 
what digits mean in mangled function names.


This would be easier if you hadn't redacted parts of the mangled name.

It's "mixin10" and "mixin11", not "109" and "119". In mangled names, 
identifiers are preceded by their lengths. In your example:


* 5 characters: the package name (whatever it actually is),
* 9 characters: subpackage name (whatever it actually is),
* 9 characters: "__mixin10",
* 9 characters: type name (whatever it actually is),
* 8 characters: "toString",
* and "MFZAya" describes the signature of toString.

Name mangling is documented here:
https://dlang.org/spec/abi.html#name_mangling

The meaning of the numbers is described in paragraph 8.

As for why "__mixin11" is referenced but "__mixin10" is being emitted, I 
have no idea. Maybe you're trying to link against an older object file?


Re: where is the memory corruption?

2020-12-09 Thread ag0aep6g via Digitalmars-d-learn

On 09.12.20 21:35, Jack wrote:
I'm on linux/opensuse, trying to pass a wchar_* from C to D but I'm 
getting only the first letter of that string. Could someone help figure 
out why?


this is the piece of D code:

extern(C) export
void sayHello(const (wchar) *s)

[...]
and below the piece of C code where I call the lib's function, compiled 
with clang -std=c11 -m64 dll.c -ldl

[...]

   const wchar_t *s2 = L"hello!";
   void (*fp)(const wchar_t*) = dlsym(lh, "sayHello");
   char *de = dlerror();
   if(de) {
     fprintf(stderr, "slsym error:%s\n", de);
     return EXIT_FAILURE;
   }
   fp(s2);

the output is "h" rather "hello". What am I missing?


D's wchar is not C's wchar_t. D's wchar is 16 bits wide. The width of 
C's wchar_t is implementation-defined. In your case it's probably 32 bits.


Because of that size mismatch, sayHello sees your L"hello!" string as 
"h\0e\0l\0l\0o\0!\0"w. And the conversion correctly stops at the first 
null character.


My C isn't very good, but I think char_16t is the correct analog to D's 
wchar. https://en.cppreference.com/w/c/string/multibyte/char16_t


Re: Are JSONOptions broken?

2020-11-28 Thread ag0aep6g via Digitalmars-d-learn

On 28.11.20 15:21, frame wrote:

This throws an UTF-exception:

auto json = JSONValue(cast(char[])[0x00, 0x7D, 0xFE, 0xFF, 0x14, 0x32, 
0x43, 0x10]);

writeln(json.toString(JSONOptions.escapeNonAsciiChars));

Makes no sense. Either the bytes should be properly escaped or there 
should not be any option if a string want to be converted to UTF anyway.


Makes perfect sense. The option is called "escapeNonAsciiChars", not 
"escapeNonUnicodeChars".



This is also fun:

auto json = JSONValue(r"\u\u007D\u00FE\u00FF\u0014\u0032\u0043\u0010");
assert(json.toString() == json.toString(JSONOptions.doNotEscapeSlashes));

and ends with:

"\\u\\u007D\\u00FE\\u00FF\\u0014\\u0032\\u0043\\u0010"


This is a slash: /
This is a backslash: \

There are no slashes in your string.


Re: implementing default opCmp

2020-11-18 Thread ag0aep6g via Digitalmars-d-learn
On Wednesday, 18 November 2020 at 22:29:17 UTC, Steven 
Schveighoffer wrote:
How do I do something really simple for opCmp? I tried this it 
didn't work:


return this == other ? 0 :
this.tupleof < other.tupleof ? -1 : 1;


std.typecons.Tuple has opCmp. So this works:

int opCmp(S other)
{
import std.typecons: tuple;
return tuple(this.tupleof).opCmp(tuple(other.tupleof));
}


Re: Packing of Struct Fields

2020-10-17 Thread ag0aep6g via Digitalmars-d-learn

On 17.10.20 14:35, Per Nordlöw wrote:

struct S
{
     int i;
     bool b;
}

struct T
{
     S s; // reinterpreting this as an array can only access this first 
element anyway
     char c; // so why can't this be aligned directly after `s` without 
any padding?

}



c does come directly after s. The padding between b and c is part of s. 
If you don't want that padding, you can use `align(1)` to define S 
without padding. But then 75% of the ints in an S[] will be misaligned.


Re: Packing of Struct Fields

2020-10-16 Thread ag0aep6g via Digitalmars-d-learn

On 16.10.20 22:32, Per Nordlöw wrote:
Why is `T.sizeof` 12 instead of 8 when `U.sizeof` is 8 in the following 
example?


struct S
{
     int i;
     bool b;
}

struct T
{
     S s;
     char c;
}

struct U
{
     int i;
     bool b;
     char c;
}

?


S.sizeof: 4 bytes for the int + 1 byte for the bool + 3 bytes padding so 
that the int is aligned = 8 bytes.


T.sizeof: 8 bytes for the S + 1 byte for the char + 3 bytes padding so 
that the S is aligned = 12 bytes.


U.sizeof: 4 bytes for the int + 1 byte for the bool + 1 byte for the 
char + 2 bytes padding so that the int is aligned = 8 bytes.


Re: Escape this in pure members

2020-09-23 Thread ag0aep6g via Digitalmars-d-learn

On 23.09.20 02:06, DlangUser38 wrote:
The following analysis might be wrong but I think that `scope` as a 
**member** function attribute is not supposed to be used as that is not 
even documented.


It's documented here:
https://dlang.org/spec/memory-safe-d.html#scope-return-params

Quote: "[`scope` and `return`] may appear after the formal parameter 
list, in which case they apply either to a method's this parameter, or 
[... irrelevant ...]."


It's less than ideal that the documentation of `scope` is spread over 
two pages.


Re: Call C variadic function from D variadic function

2020-09-13 Thread ag0aep6g via Digitalmars-d-learn

```
     /// Add a single line to an existing header
     auto addLine(T...)(RecordType type, T kvargs)
     if(kvargs.length > 0 && isSomeString!(T[0]))
     {
     static assert (kvargs.length %2 == 0);   // K-V pairs => even 
number of variadic args


     string varargMagic(size_t len)
     {
     string args = "sam_hdr_add_line(this.h, type.ptr, ";
     for(int i=0; i
[...]

Question:
If a variadic template, despite presenting to the user a "dynamic 
array", MUST know its parameter list at compile-time, is there a way 
(other than with mixins as shown) to pass this parameter list to 
extern(C) linkage function with variadic parameters?


Easy peasy:

import std.meta: Repeat;
Repeat!(kvargs.length, const(char)*) zs;
foreach (i, ref z; zs) z = toStringz(kvargs[i]);
return sam_hdr_add_line(this.h, type.ptr, zs, null);

By the way, `kvargs` is not a dynamic array. Its length is not dynamic, 
and it's not an array.


Also, you don't just want to pass the parameters forward. That would be 
trivial: `sam_hdr_add_line(this.h, type.ptr, kvargs, null)`. You want to 
run them through another function first. That's where the difficulty 
comes from.


(bonus question: if yes, can it be done with typesafe variadic function 
where I believe parameter list is known at either compile time OR 
runtime, depending on how called)


I don't see when it would matter how the function is called, but you can 
declare it in two different ways:


1) True typesafe variadic:

auto addLine(RecordType type, string[] kvargs ...)

2) Template + typesafe variadic:

auto addLine(size_t n)(RecordType type, string[n] kvargs ...)

In the first one, `kvargs.length` is a dynamic value. You can't use it 
to generate the arguments for a `sam_hdr_add_line` call.


In the second one, `kvargs.length` is a static value. So you can do the 
same things as in the `T...` template. And just like the `T...` 
template, it will generate a new function for every distinct 
`kvargs.length`.


Re: How do I copy struct having immutable pointer member when enabled DIP1000?

2020-08-30 Thread ag0aep6g via Digitalmars-d-learn

On 31.08.20 06:24, outlandkarasu wrote:
I thought that I cannot make non-scope `ref` parameters from `scope` 
array references.

But I found It allowed currently.

[...]

enum Currency : string {
     USD = "USD", EUR = "EUR", GBP = "GBP", JPY = "JPY",
}

struct Instrument {
     Currency bid;
     Currency ask;
}

struct Price {
     Instrument instrument;
     ulong value;
}

[...]

     void update(scope const(Price)[] prices) scope
     {
     foreach (price; prices)
     {
     update(price);
     }
     }

     // I thought price parameter need `scope` when called by scoped 
array elements.

     // But it can remove `scope` attribute.
     void update( /* scope */ ref const(Price) price) scope
     {
     if (minPrice.isNull || price.value < minPrice.get.value)
     {
     minPrice = price;
     }
     }


`ref` kind of implies `scope` [1]. You don't need to type it out. When 
you do type out `scope ref const(Price)`, the `scope` actually doesn't 
apply to the `ref` but to the pointers in `Price` (whereas the `scope` 
in `scope const(Price)[]` applies to the pointer of the array).


So you don't need `scope` on the `price` parameter because you're taking 
it as a `ref`. You would need `scope` if you were taking it as a pointer 
(`scope const(Price)* price`).


By the way, semantically there isn't any reason to take `price` as 
either `ref` or pointer. You can just as well take it by value, since 
you're making a copy of it anyway with `minPrice = price` (and you also 
make a copy earlier with `foreach (price; prices)`).


[...]
I also found a worried point that I can take non-scope pointer from 
non-scope `ref` parameter in DMV v2.093.1.



class MinPointerRecorder
{
@nogc nothrow pure @safe:

     void update(scope const(Price)[] prices) scope
     {
     foreach (price; prices)
     {
     update(price);
     }
     }

     void update( /* scope */ ref const(Price) price) scope
     {
     if (!minPrice || price.value < minPrice.value)
     {
     // Is this DIP1000 BUG?
     // When without DIP1000, reported compile error.
     // Error: cannot take address of parameter price
     minPrice = 
     }
     }

     const(Price)* minPrice;
}



Definitely a bug, yes. Reduced test case:


class MinPointerRecorder
{
int* minPrice;
void update(ref int price) @safe
{
minPrice =  /* Should not compile. */
}
}

void main() @safe
{
auto r = new MinPointerRecorder;
() { int mp = 42; r.update(mp); } ();
() { ulong[1000] stomp = 13; } ();
import std.stdio: writeln;
writeln(*r.minPrice); /* Prints "13". */
}


I don't think this is in Bugzilla yet. Please file an issue. Or let me 
know if you want me to do it.


https://issues.dlang.org




[1] I'm not exactly sure how it works. As far as I know, it's not 
documented anywhere.


Re: How do I copy struct having immutable pointer member when enabled DIP1000?

2020-08-30 Thread ag0aep6g via Digitalmars-d-learn

On 30.08.20 17:24, outlandkarasu wrote:


enum Tag { tag = "tag" }

struct A { Tag tag; }

A createA() @safe
{
     scope a = A(Tag.tag);

     // Error: scope variable a may not be returned
     return a;

     // NG
     // return A(a);
     // return A(a.tag);
}


[...]

I understand those errors are DIP1000 language design.
However I suppose that DIP1000 check can permit immutable pointer in 
some cases.


If I understand correctly, your point is that an enum pointer is 
guaranteed to refer to static data, so it could be exempt from `scope` 
checks.


At a glance, that makes sense to me. But I guess one question is whether 
it's possible to create an enum value that points to the stack. A cast 
does the trick:


immutable char[1] c = 'e';
E e = cast(E) c[];

DMD accepts it as @safe, implying that the cast is valid and that `e` is 
a safe value. If that is correct, then enum pointers are actually not 
guaranteed to refer to static data. They can just as well point to the 
stack. Consequently, an enum pointer must be treated like a plain 
pointer. I.e., `scope` must treat a `Tag` just like a plain `string`.



Is there a better workaround, practices or patterns?


In your example, you can just remove the `scope` annotation. Why mark a 
local that you want to return with `scope`? Doesn't make sense


But I guess your actual use case isn't as simple. Maybe you can show a 
less reduced version of the code where simply removing `scope` is not an 
option?


Re: in; scope; scope ref; DIP1000; documentation

2020-08-27 Thread ag0aep6g via Digitalmars-d-learn

On 27.08.20 20:49, James Blachly wrote:
1. The thread involves 'in' qualifier. Documentation 
(https://dlang.org/spec/function.html#param-storage) indicates that `in` 
is defined as `scope const` and should not be used as it is not 
implemented. **Is this [fact and recommendation] still true?**


There is this:

https://dlang.org/changelog/2.092.0.html#preview-in

Which says that `in` is planned to become `const scope` in the future 
and there is a preview switch for it: `-preview=in`.


But these are both false (with and without `-preview=in`):

is(void function (in int* x) == void function (const int* x))
is(void function (in int* x) == void function (scope const int* x))

So `in` is not strictly equivalent to anything else. I'd say the 
recommendation is good: Avoid `in` until that stuff is sorted out and 
`in` actually gets lowered to `scope const` (or whatever it ends up 
meaning).


[...]
Is "scope ref" documented somewhere specifically? I found 
https://dlang.org/spec/function.html#scope-parameters which discusses 
the use of `scope` with ref type parameters, but the example given is 
pointer-based. Is it correct that `scope ref T` behaves the same as 
`scope T*` ?


I don't think there's documentation for `scope ref`. That may be because 
`scope` doesn't affect `ref`. This is a corner of DIP 1000 that keeps 
confusing me.


Consider this function:

int* fp(scope int** p) { return *p; }

This compiles with `-preview=dip1000`. That's because the `scope` only 
applies to the outer pointer. It doesn't apply to the inner one. So 
returning the inner pointer is fine. At least, that's how I understand 
DIP 1000.


Now consider this one:

int* fr(scope ref int* r) { return r; }

One might expect the same result for fr. A `ref` is pretty much the same 
thing as a pointer, isn't it? But you actually get an error: "scope 
variable `r` may not be returned". I think that's because the `scope` 
doesn't apply to the `ref` part of the parameter; it applies to the pointer.


Similarly, this compiles:

int* fp(int* p) { return p; }

But this doesn't:

int* fr(ref int r) { return  }

Apparently, a `ref` is not "pretty much the same thing as a pointer". 
It's more restricted. It acts like a `scope` pointer without needing the 
`scope` annotation. Unfortunately, this isn't documented, as far as I 
can tell.


Regarding `scope` more generally, DIP1000 shows as "superseded" -- **can 
I still rely on this document for guidance?** We have a `-dip1000` flag 
but a superseded DIP. The discordance is extremely confusing.



I am glad D is iterating quickly and improving on safety, but I have 
found that documentation may not well recent changes in this area.


Agreed. The documentation is in a bad state. The information is spread 
over documents, forum posts, and of course the implementation in DMD. 
And all of those are wrong/outdated in parts.


Regarding the different sources of information:

1) Start with the spec 
(). Unlike DIP 
documents, the spec is being updated. It might be incomplete or have 
errors, but it at least has a chance to get fixed.


2) Ignore the DIP document 
(). 
Only refer to it as a last resort. Any other source is more likely to be 
correct.


3) Do check what the compiler does, but don't trust it blindly. The 
implementation still has some serious bugs. A personal favorite: 



4) Bugzilla (): If a bug report demonstrates a 
safety violation with only @safe code, it's valid. If it doesn't, 
there's a significant chance that the reporter missed some detail about 
`scope` and the issue ends up being invalid.


Consequently I am reluctant to use (newer) features related to memory 
safety. If this is all comprehensively documented somewhere please let 
me know!


For the time being, I think it's perfectly fine to ignore 
`-preview=dip1000`. The feature is clearly not finished.


Re: String mixin from within a template

2020-08-23 Thread ag0aep6g via Digitalmars-d-learn

On Sunday, 23 August 2020 at 20:54:22 UTC, data pulverizer wrote:

compiled string 1: alias x0 = Remove(indicies[i] - i, Args);
Error: found - when expecting )
Error: semicolon expected to close alias declaration
Error: no identifier for declarator i
Error: declaration expected, not ,
... repeated for the other two cases ...


As the compiler tells you, the line

alias x0 = Remove(indicies[i] - i, Args);

doesn't parse.

You can't assign the result of a function call to an `alias`.
If `Remove` is indeed a function, you need to use `enum` instead 
of `alias`.

If `Remove` is a template, you're missing an exclamation mark.

You also have a typo: "indicies" should be "indices".


Re: String mixin from within a template

2020-08-23 Thread ag0aep6g via Digitalmars-d-learn

On Sunday, 23 August 2020 at 19:42:47 UTC, data pulverizer wrote:

`alias x` ~ i ~ ` = Remove(indexes[i] - i, x`~ (i - 1) ~ `);`

[...]

```d
Error: no identifier for declarator x
```

Indicating that the concatenation `~` is not working, and I 
only get the partial string when I print out `pragma(msg, 
_string_);`


You're having a misconception about concatenation.

This:

"foo " ~ 65 ~ " bar"

does not produce the string "foo 65 bar". It produces the string 
"foo A bar", because 65 == 'A'. In your case, when i == 0, you 
get a null byte in the string, which is probably the cause for 
the partial output.


You can use std.conv or std.format to make a string from a number:

text("foo ", 65, " bar")
format("foo %s bar", 65)


Re: Template constraint on alias template parameter.

2020-08-06 Thread ag0aep6g via Digitalmars-d-learn

On Thursday, 6 August 2020 at 16:01:35 UTC, jmh530 wrote:
The code below compiles, but I want to put an additional 
constraint on the `test` function is only called with a Foo 
struct.


I tried things like is(T == Foo) and is(T : Foo), but those 
don't work. However, something like is(T!int : Foo!int) works, 
but is(T!U == Foo!U, U) doesn't. Any idea why is(T!U == Foo!U, 
U) doesn't work?


struct Foo(T)
{
T x;
}

void test(alias T)()
if (__traits(isTemplate, T))
{
import std.stdio: writeln;
writeln("there");
}

void main()
{
test!Foo();
}


`is(...)` only works on types. You're looking for 
`__traits(isSame, T, Foo)`.


For `is(T!U == Foo!U, U)` to work, the compiler would have to 
guess U. If the first guess doesn't work, it would have to guess 
again, and again, and again, until it finds a U that does work. 
Could take forever.


Re: dynamic array .length vs .reserve - what's the difference?

2020-07-31 Thread ag0aep6g via Digitalmars-d-learn

On 31.07.20 01:42, wjoe wrote:
I could swear just a few weeks ago there was someone asking how to tell 
if an array was null or of length 0 and an answer was that it's the same 
and can't be distinguished so I assumed that assigning a slice of 0 
length is the same as setting the array to null because the result is 
the same as a 0 length array.


This one?
https://forum.dlang.org/thread/xgnbzpziqmjyjfsql...@forum.dlang.org

`[]` is the same as `null`.

While `b[0 .. 0]` is empty like `[]`, it is not the same (unless `b` is 
already `[]`/`null`). The `.ptr`s are different.


Re: constructing labels for static foreach inside switch inside foreach

2020-07-08 Thread ag0aep6g via Digitalmars-d-learn

On 08.07.20 14:24, Steven Schveighoffer wrote:
I solved it for now by extrapolating the inner code into a local 
template function. But this is definitely an awkward situation for 
static foreach.


FWIW, you can write the extra function like this:

static foreach (T; Types)
() {
innerloop: while (haveMoreData)
{
...
break innerloop;
...
}
} ();


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

2020-06-29 Thread ag0aep6g via Digitalmars-d-learn

On 29.06.20 02:28, Stanislav Blinov wrote:

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.


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.


Re: isInputRange not satisfied even if all individual conditions are satisfied

2020-06-26 Thread ag0aep6g via Digitalmars-d-learn

On 26.06.20 15:35, ag0aep6g wrote:
`isInputRange!R` fails because it has no knowledge of your free `empty` 
function. Without `empty`, `R` is obviously not a range.


To be clear: It's the same with `front` and `popFront`. You can't 
implement any range primitives as free functions.


It only works for arrays because those implementations are part of 
std.range.


Re: isInputRange not satisfied even if all individual conditions are satisfied

2020-06-26 Thread ag0aep6g via Digitalmars-d-learn

On 26.06.20 15:09, Johannes Loher wrote:

import std.meta : allSatisfy, staticMap;
import std.traits : allSameType;
import std.range : isInputRange, ElementType, empty;

[...]

@property bool empty(TypeArgs...)(auto ref scope SumType!(TypeArgs) r)
 if (allSatisfy!(isInputRange, TypeArgs) && TypeArgs.length > 0)
{
 return r.match!(staticMap!(EmptyLambda, TypeArgs));
}

[...]

enum bool myIsInputRange(R) =
 is(typeof(R.init) == R)
 && is(ReturnType!((R r) => r.empty) == bool)
 && is(typeof((return ref R r) => r.front))
 && !is(ReturnType!((R r) => r.front) == void)
 && is(typeof((R r) => r.popFront));

void main() {

[...]

 import std.traits : ReturnType;

[...]

 alias R = SumType!(typeof(i), typeof(o));

 // all individual conditions of `isInputRange` are satisfied
 static assert(is(typeof(R.init) == R));
 static assert(is(ReturnType!((R r) => r.empty) == bool));

[...]

 // but `isInputRange` is not satisfied
 static assert(!isInputRange!(R));

 // and neither is a local copy
 static assert(!myIsInputRange!(R));
}


`isInputRange!R` fails because it has no knowledge of your free `empty` 
function. Without `empty`, `R` is obviously not a range.


`myIsInputRange!R` fails because you forgot to import `ReturnType` in 
module scope. You're importing it locally in `main`, so the check passes 
there.


Re: Metaprogramming with D

2020-06-09 Thread ag0aep6g via Digitalmars-d-learn

On 09.06.20 20:16, Ali Çehreli wrote:
I am biased but I like my :) index of the book, where all such syntax 
items appear:


   https://ddili.org/ders/d.en/ix.html


Oh yeah. It's how I got the link. You might want to fix some of the 
URLs, though. Characters like '{' or '[' need to be percent-encoded.


Re: Metaprogramming with D

2020-06-08 Thread ag0aep6g via Digitalmars-d-learn

On 08.06.20 16:45, ag0aep6g wrote:

On 08.06.20 16:41, Jan Hönig wrote:

On Sunday, 7 June 2020 at 00:45:37 UTC, Ali Çehreli wrote:

[...]

  writeln(q{
  void foo() {
  }
    });


What is the name of this `q` thing?
How do i find it? Are there any recent tutorials on it?


https://dlang.org/spec/lex.html#token_strings
https://ddili.org/ders/d.en/literals.html#ix_literals.q{}


Hm. That second link is somewhat malformed. Better one:
https://ddili.org/ders/d.en/literals.html#ix_literals.q%7B%7D


Re: Metaprogramming with D

2020-06-08 Thread ag0aep6g via Digitalmars-d-learn

On 08.06.20 16:41, Jan Hönig wrote:

On Sunday, 7 June 2020 at 00:45:37 UTC, Ali Çehreli wrote:

[...]

  writeln(q{
  void foo() {
  }
    });


What is the name of this `q` thing?
How do i find it? Are there any recent tutorials on it?


https://dlang.org/spec/lex.html#token_strings
https://ddili.org/ders/d.en/literals.html#ix_literals.q{}


Re: Mixin and imports

2020-06-08 Thread ag0aep6g via Digitalmars-d-learn

On 08.06.20 16:27, data pulverizer wrote:
Out of curiosity what does the "." in front of `foo` mean? I've seen 
that in some D code on the compiler in GitHub and have no idea what it 
does. I tried Googling it to no avail. It doesn't have anything to do 
with UFCS does it?


https://dlang.org/spec/module.html#module_scope_operators


Re: Use classes as keys in associative array

2020-06-06 Thread ag0aep6g via Digitalmars-d-learn

On Saturday, 6 June 2020 at 16:49:29 UTC, JN wrote:
Is it possible to use different class instances as keys for 
associative array, but compare them by the contents? I tried to 
override opEquals but it doesn't seem to work.


You also need toHash.

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


Re: Determining @trusted-status

2020-05-29 Thread ag0aep6g via Digitalmars-d-learn

On 29.05.20 08:28, JN wrote:
Alternatively you could just use @trusted blocks. Unsafe blocks are a 
common practice in languages like C# or Rust when it comes to calling 
unsafe code. @safe isn't about 100% bulletproof safety. @safe is (should 
be) about not having memory related errors outside of @trusted code, 
minimizing the surface area for errors.


Note that an "@trusted block" is really a nested @trusted function being 
called immediately. Being an @trusted function, the "block" must have a 
safe interface. I.e., its safety cannot depend on its inputs. The inputs 
of a nested function include the variables of the surrounding function. 
@trusted blocks often violate the letter of @trusted law, because people 
forget/ignore that.


For example, the second @trusted block here is strictly speaking not 
allowed, because its safety depends on `p`:


void main() @safe
{
import core.stdc.stdlib: free, malloc;
int* p = () @trusted {
return cast(int*) malloc(int.sizeof);
} ();
if (p is null) return;
/* ... else: do something with p ... */
() @trusted { free(p); } ();
}


Re: Determining @trusted-status

2020-05-29 Thread ag0aep6g via Digitalmars-d-learn

On 29.05.20 02:09, Clarice wrote:
It seems that @safe will be de jure, whether by the current state of 
DIP1028 or otherwise. However, I'm unsure how to responsibly determine 
whether a FFI may be @trusted: the type signature and the body. Should I 
run, for example, a C library through valgrind to observe any memory 
leaks/corruption? Is it enough to trust the authors of a library (e.g. 
SDL and OpenAL) where applying @trusted is acceptable?
There's probably no one right answer, but I'd be very thankful for some 
clarity, regardless.


There are two ways in which a function can be unsafe:

1) The function has a bug and doesn't behave as intended.
2) The function doesn't have a safe interface [1].

When applying @trusted, you are allowed to pretend that #1 doesn't 
happen. You are allowed to trust that the author of the library made no 
safety-critical mistakes.


What you have to look out for is #2. When a function has special 
requirements for how to call it, and calling it incorrectly can lead to 
undefined behavior / memory corruption, then it cannot be @trusted. It 
can only be @system. In order to use the function in @safe code, you 
need to write an @trusted wrapper that provides a safe interface and 
makes sure that the @system function is called correctly.



[1] https://dlang.org/spec/function.html#safe-interfaces


Re: How to get the pointer of "this" ?

2020-05-26 Thread ag0aep6g via Digitalmars-d-learn

On 26.05.20 15:43, Vinod K Chandran wrote:

So far now, two solutions are very clear for this problem.
1. As per John Chapman's suggestion - use cast(DWORD_PTR)cast(void*)this).
2. Use another varibale to use as an lvalue. -
  Button dummyBtn = this;
  cast(DWORD_PTR)
Among these two, i think 2nd option is good. Am i right ?


No. Use option 1.


Re: Variable "i" can not be read at compile time

2020-05-24 Thread ag0aep6g via Digitalmars-d-learn

On 24.05.20 19:13, data pulverizer wrote:
Thank you very much. I though that if I used a `static foreach` loop D 
would attempt to run the calculation `bench()` at compile time rather 
than at run time but it doesn't which is good. So `static foreach` 
allows you to index at compile time and if its scope runs at run time it 
is run time and if at compile time it is compile time evaluated?


`static foreach` gets unrolled at compile time. It doesn't affect how 
the body is handled. It's like copy-pasting the loop body n times in the 
source code.


For example, this:

int x = 0;
static foreach (i; 0 .. 3)
{
x += f(i);
}

is the same this:

int x = 0;
x += f(0);
x += f(1);
x += f(2);

It doesn't affect how `f` is being run. They're ordinary run-time calls 
either way.


To evaluate the `f` calls during compilation you can use `enum` to 
trigger CTFE:


int x = 0;
enum f0 = f(0); /* CTFE */
x += f0;
enum f1 = f(1); /* CTFE */
x += f1;
enum f2 = f(2); /* CTFE */
x += f2;

or with `static foreach`:

int x = 0;
static foreach (i; 0 .. 3)
{{
enum e = f(i);
x += e;
}}

Notice the extra set of braces. It's just adding a scope. Without that, 
the different `e`s would clash with each other.


Re: Variable "i" can not be read at compile time

2020-05-24 Thread ag0aep6g via Digitalmars-d-learn

On 24.05.20 18:34, data pulverizer wrote:

I'm getting the error:

```
Error: variable i cannot be read at compile time
Error: template instance 
script.runKernelBenchmarks!(Tuple!(DotProduct!float, Gaussian!float, 
Polynomial!float, Exponential!float, Log!float, Cauchy!float, 
Power!float, Wave!float, Sigmoid!float)) error instantiating

```

When I run ...

```
...
auto runKernelBenchmarks(KS)(KS kernels, long[] n, bool verbose = true)
{
   auto tmp = bench(kernels[0], n, verbose);
   alias R = typeof(tmp);
   R[] results = new R[kernels.length];
   results[0] = tmp;
   for(size_t i = 1; i < results.length; ++i)
   {
     results[i] = bench(kernels[i], n, verbose);
   }
   return results;
}

void main()
{
   alias T = float;
   auto kernels = tuple(DotProduct!(T)(),   Gaussian!(T)(1), 
Polynomial!(T)(2.5f, 1),

    Exponential!(T)(1), Log!(T)(3), Cauchy!(T)(1),
    Power!(T)(2.5f),    Wave!(T)(1), Sigmoid!(T)(1, 
1));

   string[] kernelNames = ["DotProduct",  "Gaussian", "Polynomial",
    "Exponential", "Log",  "Cauchy",
    "Power",   "Wave", "Sigmoid"];
   long[] n = [100L, 500L, 1000L];
   auto results = runKernelBenchmarks(kernels, n);
   writeln("Results: ", results);
}
```


Since `kernel` is a `Tuple`, you can only access it with compile-time 
constant indices.


But your loop variable `i` is not a compile-time constant, it's being 
calculated at run time. What's more, it depends on `results.length` 
which is also not a compile-time constant. But `results.length` is the 
same as `kernels.length`. And being the length of a `Tuple`, that one is 
a compile-time constant.


So you can rewrite your loop as a `static foreach` (which is evaluated 
during compile-time) using `kernels.length` instead of `results.length`:


static foreach (i; 1 .. kernels.length)
{
results[i] = bench(kernels[i], n, verbose);
}


Re: Distinguish between a null array and an empty array

2020-05-24 Thread ag0aep6g via Digitalmars-d-learn

On 24.05.20 14:29, bauss wrote:
Dang, that sucks there is no proper way and I would say that's a big 
flaw of D.


Because what I need it for is for some data serialization but if the 
value is an empty array then it should be present and if it's null then 
it should not be present.


Since null is used to say "ignore this" in the data serialization.


You can use std.typecons.Nullable (or a similar wrapper) to add an extra 
"ignore this" value to a type.


Re: Distinguish between a null array and an empty array

2020-05-24 Thread ag0aep6g via Digitalmars-d-learn

On 24.05.20 14:12, bauss wrote:

Is there a way to do that?

Since the following are both true:

int[] a = null;
int[] b = [];

assert(a is null);
assert(!a.length);

assert(b is null);
assert(!b.length);

What I would like is to tell that b is an empty array and a is a null 
array.


No way. `null` and `[]` are the same thing for arrays. (Ulike `""` for 
strings which has a non-null `.ptr`.)


You can distinguish `null` from other (non-null, non-`[]`) empty arrays. 
For example:



int[] b = [1, 2, 3];
b = b[0 .. 0];

assert(b !is null);
assert(!b.length);



Re: Why does indexing a string inside of a recursive call yield a different result?

2020-05-10 Thread ag0aep6g via Digitalmars-d-learn

On 10.05.20 12:02, Adnan wrote:

ulong editDistance(const string a, const string b) {
     if (a.length == 0)
     return b.length;
     if (b.length == 0)
     return a.length;

     const auto delt = a[$ - 1] == b[$ - 1] ? 0 : 1;

     import std.algorithm : min;

     return min(
     editDistance(a[0 .. $ - 1], b[0 .. $ - 1]) + delt,
     editDistance(a, b[0 .. $ - 1]) + 1,
     editDistance(a[0 .. $ - 1], b) + 1
     );
}

This yields the expected results but if I replace delt with its 
definition it always returns 1 on non-empty strings:


ulong editDistance(const string a, const string b) {
     if (a.length == 0)
     return b.length;
     if (b.length == 0)
     return a.length;

     //const auto delt = a[$ - 1] == b[$ - 1] ? 0 : 1;

     import std.algorithm : min;

     return min(
     editDistance(a[0 .. $ - 1], b[0 .. $ - 1]) + a[$ - 1] == b[$ - 
1] ? 0 : 1, //delt,

     editDistance(a, b[0 .. $ - 1]) + 1,
     editDistance(a[0 .. $ - 1], b) + 1
     );
}

Why does this result change?


You're going from this (simplified):

delt = a == b ? 0 : 1
result = x + delt

to this:

result = x + a == b ? 0 : 1

But that new one isn't equivalent to the old one. The new one actually 
means:


result = (x + a == b) ? 0 : 1

You need parentheses around the ternary expression:

result = x + (a == b ? 0 : 1)


Re: CTFE and Static If Question

2020-05-07 Thread ag0aep6g via Digitalmars-d-learn

On 07.05.20 17:00, jmh530 wrote:

Does foo!y0(rt) generate the same code as foo(rt, y0)?

How is the code generated by foo(rt, x0) different from foo(rt,y0)?

auto foo(bool rtct)(int rt) {
     static if (rtct)
     return rt + 1;
     else
     return rt;
}

auto foo(int rt, bool rtct) {
     if (rtct == true)
     return rt + 1;
     else
     return rt;
}

void main() {
     int rt = 3;
     bool x0 = true;
     bool x1 = false;
     assert(foo(rt, x0) == 4);
     assert(foo(rt, x1) == 3);

     enum y0 = true;
     enum y1 = false;
     assert(foo!y0(rt) == 4);
     assert(foo!y1(rt) == 3);
     assert(foo(rt, y0) == 4);
     assert(foo(rt, y1) == 3);
}


The `static if` is guaranteed to be evaluated during compilation. That 
means, `foo!y0` effectively becomes this:


auto foo(int rt) { return rt + 1; }

There is no such guarantee for `foo(rt, y0)`. It doesn't matter that y0 
is an enum.


But a half-decent optimizer will have no problem replacing all your 
calls with their results. Compared with LDC and GDC, DMD has a poor 
optimizer, but even DMD turns this:


int main() {
int rt = 3;
bool x0 = true;
bool x1 = false;
enum y0 = true;
enum y1 = false;
return
foo(rt, x0) +
foo(rt, x1) +
foo!y0(rt) +
foo!y1(rt) +
foo(rt, y0) +
foo(rt, y1);
}

into this:

int main() { return 21; }


Re: Thread to watch keyboard during main's infinite loop

2020-05-06 Thread ag0aep6g via Digitalmars-d-learn

On 07.05.20 02:13, Daren Scot Wilson wrote:

import std.stdio;
import core.stdc.stdio;  // for getchar().  There's nothing similar in D 
std libs?

import std.concurrency;
import core.thread; // just for sleep()


Instead of the comment you can write:

import core.thread: sleep;


bool running=true;
char command = '?';


These variables are thread-local by default. That means independent 
`running` and `command` variables are created for every thread. If you 
make changes in one thread, they won't be visible in another thread.


Use `shared` so that all threads use the same variables:

shared bool running=true;
shared char command = '?';


void cmdwatcher()
{
     writeln("Key Watcher");
     while (running)  {
     char c = cast(char)getchar();
     if (c>=' ')  {
     command = c;
     writefln(" key %c  %04X", c, c);
     }
     }
}

void main()
{
     writeln("Start main");
     spawn();

     while (running) {
     writeln("Repetitive work");
     Thread.sleep( dur!("msecs")( 900 ) );

     char cmd = command;  // local copy can't change during rest of 
this loop


For values that don't change, we've got `immutable`:

immutable char cmd = command;


     command = ' ';


Note that even when using `shared` you still have to think hard to avoid 
race conditions.


This sequence of events is entirely possible:

1) main: cmd = command
2) cmdwatcher: command = c
3) main: command = ' '

It won't happen often, but if it does, your input has no effect.


Re: Help, what is the code mean?

2020-04-28 Thread ag0aep6g via Digitalmars-d-learn

On Tuesday, 28 April 2020 at 20:48:57 UTC, Net wrote:

() { ... } ();

Is there a name of this kind of function in D? unnamed? 
anonymous?


The spec uses "anonymous". Syntactically, `() { ... }` is a 
function literal.


There is a section called "Anonymous Functions and Anonymous 
Delegates" [1], but it's just a link to "Function Literals":


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

To be clear, the second set of parentheses in `() { ... } ()` 
just calls the anonymous function. You could equivalently write 
it like this:


alias f = () { ... };
f();


[1] https://dlang.org/spec/function.html#anonymous


Re: Flatten a range of static arrays

2020-02-08 Thread ag0aep6g via Digitalmars-d-learn

On 08.02.20 07:27, ag0aep6g wrote:

On 08.02.20 02:38, ag0aep6g wrote:

Simplified, we're looking at this:


struct Joiner
{
 int[3] _items;
 int[] _current;
}
void main() @safe
{
 Joiner j;
 j._current = j._items[];
}


[...]
In the first reduction, `j` might be `scope`, but `j._items` has no 
indirections. `scope` doesn't actually mean anything for it. It's just 
an `int[3]` on the stack. So taking its address could be allowed.


But (the current implementation of) DIP 1000 is apparently too 
conservative for that. It seems to treat pointers into a struct the same 
as pointers to the whole thing.


My attempt at lifting this limitation:

https://github.com/dlang/dmd/pull/10773


Re: Flatten a range of static arrays

2020-02-08 Thread ag0aep6g via Digitalmars-d-learn

On 08.02.20 15:57, Steven Schveighoffer wrote:
This kind of stuff is so difficult to reason about and develop as a 
library that people will just end up removing dip1000 from their 
compilation.


I 100% agree that DIP 1000 is hard to reason about. It's pretty limited 
by design, and the implementation has so many bugs. If anyone has a 
better design (and implementation), I'd be all for that.


About just ditching the compiler switch: Then you can't even take the 
address of a local. Also, it's going to become the default eventually.


Re: Flatten a range of static arrays

2020-02-07 Thread ag0aep6g via Digitalmars-d-learn

On 08.02.20 02:38, ag0aep6g wrote:

Simplified, we're looking at this:


struct Joiner
{
     int[3] _items;
     int[] _current;
}
void main() @safe
{
     Joiner j;
     j._current = j._items[];
}


I.e., a self-referential struct. Or most fundamentally:


struct Joiner
{
     Joiner* p;
}
void main() @safe
{
     Joiner j;
     j.p =  /* error */
}


`dmd -dip1000` complains about the marked line:

     Error: reference to local variable j assigned to non-scope j.p

What if I mark `j` as `scope`? Then I should be able to assign a 
reference-to-local to `j.p`. Indeed, the error goes away, but another 
takes its place:


     Error: cannot take address of scope local j in @safe function main

Right. That can't be allowed, because `scope` gives only one level of 
protection, and `` would need two (one for `j` itself and one for the 
thing it points at).


I went a bit overboard with that second reduction. The original struct 
is self-referential, but it's not recursive. The errors are the same for 
the first reduction. But it's not as clear that they're necessary.


In the first reduction, `j` might be `scope`, but `j._items` has no 
indirections. `scope` doesn't actually mean anything for it. It's just 
an `int[3]` on the stack. So taking its address could be allowed.


But (the current implementation of) DIP 1000 is apparently too 
conservative for that. It seems to treat pointers into a struct the same 
as pointers to the whole thing.


Re: Flatten a range of static arrays

2020-02-07 Thread ag0aep6g via Digitalmars-d-learn

On 08.02.20 01:17, Steven Schveighoffer wrote:
The original code is not invalid though. f is not valid, and that is a 
bug, but the original code posted by nullptr should be fine by memory 
safety standards.


Maybe. But then it should also work with `int[3] front;`.

If there is no possible way to do the original code with dip1000 
attributes, then that's a bug with dip1000's design (would not be 
surprised).


Or DIP 1000 just doesn't allow that kind of code. @safe (including DIP 
1000) is not supposed to allow all de-facto safe programs.


Simplified, we're looking at this:


struct Joiner
{
int[3] _items;
int[] _current;
}
void main() @safe
{
Joiner j;
j._current = j._items[];
}


I.e., a self-referential struct. Or most fundamentally:


struct Joiner
{
Joiner* p;
}
void main() @safe
{
Joiner j;
j.p =  /* error */
}


`dmd -dip1000` complains about the marked line:

Error: reference to local variable j assigned to non-scope j.p

What if I mark `j` as `scope`? Then I should be able to assign a 
reference-to-local to `j.p`. Indeed, the error goes away, but another 
takes its place:


Error: cannot take address of scope local j in @safe function main

Right. That can't be allowed, because `scope` gives only one level of 
protection, and `` would need two (one for `j` itself and one for the 
thing it points at).


If that code were allowed, you could do this:


struct Joiner
{
Joiner* p;
}
Joiner g;
void main() @safe
{
scope Joiner j;
() @trusted { j.p =  } (); /* pretend it's allowed */
g = *j.p; /* dereference and copy */
}


Returning a copy of a dereferenced `scope` pointer is always allowed, 
because `scope` only provides one level of protection.


Re: Flatten a range of static arrays

2020-02-07 Thread ag0aep6g via Digitalmars-d-learn

On 08.02.20 00:10, nullptr wrote:

```
import std;

struct SomeRange
{
     int[3] val;

     enum empty = false;

     auto popFront() @safe {}

     ref auto front() @safe
     {
     return val;
     }
}

void main() @safe
{
     SomeRange().take(10).map!((return ref x) => x[]).joiner.writeln;
}
```

I don't know how applicable this is to your use case, but this code will 
compile and run under -dip1000.


That shouldn't compile. You have found a hole in DIP 1000.


struct SomeRange
{
int[3] val = [10, 20, 30];
ref auto front() @safe { return val; }
}

int[] f() @safe
{
SomeRange sr;
// return sr.val[]; /* error, as expected */
return sr.front[]; /* no error, but escapes reference to local */
}

void main() @safe
{
auto x = f();
import std.stdio;
writeln(x); /* Prints garbage. */
}


I'm too lazy right now to check if it's already in Bugzilla.


Re: Cannot take slice of scope static array in @safe code

2020-02-02 Thread ag0aep6g via Digitalmars-d-learn

On 02.02.20 19:49, ag0aep6g wrote:

On 02.02.20 19:18, Steven Schveighoffer wrote:
I'm not sure if I got it right, but like this?

     int*[][] g1;
     int*[] g2;
     int* g3;

     void main() @safe
     {
     /* An array stored on the stack, of references to heap data: */
     int*[3] a1 = [new int, new int, new int];
     /* Another such array: */
     int*[3] a2 = [new int, new int, new int];
     /* An array of those arrays, stored on the stack: */
     int*[][2] b = [a1[], a2[]];

     g1 = b[]; /* Nope. */
     g2 = b[0]; /* Nope. */
     g3 = b[0][0]; /* Ok. */
     }


I guess I kinda missed the point there, and what you want is this:

scope int*[][] slice = b[];
/* ... use `slice` in non-leaky ways ... */

Which DIP 1000 doesn't allow, because it wouldn't be able to ensure that 
the references to a1 and a2 don't leak. Yeah, DIP 1000 falls somewhat short.


Re: Cannot take slice of scope static array in @safe code

2020-02-02 Thread ag0aep6g via Digitalmars-d-learn

On 02.02.20 19:18, Steven Schveighoffer wrote:

On 2/2/20 10:20 AM, ag0aep6g wrote:

[...]

 void main() @safe
 {
 int* a0;
 scope int** b0 =  /* accepted */

 scope int* a2;
 scope int** b2 =  /* rejected */
 }

Now it's important to realize that `scope` only applies to the 
top-level of the type. That means, when you dereference b0 or b2, you 
get a plain `int*` without any `scope` on it.


I think this is wrong. a0 is not a scope array of scope strings, it's a 
scope array of strings. string isn't scope, it points to immutable data 
that's on the heap or in the static segment (generally).


I don't follow. In my code, a0's type is `int*`. In the original code 
it's `string[1]`. Neither of them are `scope`.


[...]
How does one declare "I have this array which is scope, because it's 
storage is on the stack. But it points at things that are in the GC 
heap, so it's cool to reference those without scope."


As far as I understand, you're describing what `scope` does:

int[][] g1;
int[] g2;
void main() @safe
{
int[][3] arr = [[1, 2], [3, 4], [5, 6]];
int[][] slice = arr[]; /* Inferred `scope`. */
g1 = slice; /* Nope. `slice` is `scope`. */
g2 = slice[0]; /* Ok. `slice[0]` is not `scope`. */
}

And if that is a simple matter, what about an array stored on the stack 
of arrays stored on the stack, of references to heap data? How do I make 
sure the heap pointers are still heap pointers, and not have to cast the 
compiler into submission?

I'm not sure if I got it right, but like this?

int*[][] g1;
int*[] g2;
int* g3;

void main() @safe
{
/* An array stored on the stack, of references to heap data: */
int*[3] a1 = [new int, new int, new int];
/* Another such array: */
int*[3] a2 = [new int, new int, new int];
/* An array of those arrays, stored on the stack: */
int*[][2] b = [a1[], a2[]];

g1 = b[]; /* Nope. */
g2 = b[0]; /* Nope. */
g3 = b[0][0]; /* Ok. */
}

I've run into problems like this before, they aren't solvable with 
dip1000. And string arrays are usually where it stops working because of 
the double indirection.


My experience with DIP 1000 is more that it has many holes where leaks 
don't get detected. That has made it difficult for me to form an 
understanding of what is supposed to work and what isn't. I'd like to 
believe that I got it by now, but I'm not really sure.


Re: Cannot take slice of scope static array in @safe code

2020-02-02 Thread ag0aep6g via Digitalmars-d-learn

On 02.02.20 14:40, Dennis wrote:

Compiling the following with -dip1000 gives an error.

```
void main() @safe {
     string[1] a0;
     scope int[1] a1;
     scope string[1] a2;

     scope string[] b0 = a0[]; // Fine
     scope int[] b1 = a1[]; // Fine
     scope string[] b2 = a2[]; // Error: cannot take address of scope 
local a2

}
```

Can anyone explain why? I don't see how b2 violates the scope constraint 
of a2.


To make this easier, let's:

1) type out `string` as `immutable(char)[]`,
2) throw that `immutable` away, because it doesn't matter,
3) replace the arrays with pointers.

Then we're looking at this:

void main() @safe
{
int* a0;
scope int** b0 =  /* accepted */

scope int* a2;
scope int** b2 =  /* rejected */
}

Now it's important to realize that `scope` only applies to the top-level 
of the type. That means, when you dereference b0 or b2, you get a plain 
`int*` without any `scope` on it.


For b0 that's fine, because a0 isn't `scope` (neither explicit nor 
inferred).


But for b2 it would be a problem, because a2 would lose its `scope`. 
That can't be allowed.



It might be a compiler bug, but since the int[] case works


With regards to DIP 1000, `string` is very different from `int`. 
`string` has an indirection. `int` doesn't. The analogous type to 
`string[]` is `int[][]`.


Re: template instantiation problems

2020-01-10 Thread ag0aep6g via Digitalmars-d-learn

On 10.01.20 18:27, berni44 wrote:
This clearly shows, that packageName is only instatiated once at top 
level although mod0 and mod1 are two different things (at least their 
stringof produces different results) and therefore should be 
instantiated twice.


Now I don't know if this is a bug in DMD or I should know something I do 
not know... Can you help me?



import m1 = foo.baz;
import m2 = foo;
alias p = __traits(parent, m1);

pragma(msg, m1.stringof); /* "module baz", ok */
pragma(msg, m2.stringof); /* "module foo", ok */
pragma(msg, p.stringof); /* "package foo", ok */

enum e(alias thing) = thing.stringof;

pragma(msg, e!m1); /* "module baz", ok */
pragma(msg, e!m2); /* "module foo", ok */
pragma(msg, e!p); /* "module foo", wat?? */


If you switch the last two lines around, you get "package foo" twice.

The compiler apparently thinks that m2 (module foo) and p (package foo) 
are the same thing when used as a template argument. So it reuses the 
previous result.


There's a similar issue with values:

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


Re: Difference between slice[] and slice

2019-09-25 Thread ag0aep6g via Digitalmars-d-learn

On 25.09.19 22:36, WhatMeWorry wrote:

On Wednesday, 25 September 2019 at 19:25:06 UTC, Ali Çehreli wrote:

On 09/25/2019 12:06 PM, WhatMeWorry wrote:

[...]

> In short, is there anytime that one would want to use
"slice[] =
> something" syntax?I

That changes element values.


Ok.  But which element(s)?


All of them. For example, `slice[] = 42;` sets all elements to 42. And 
`slice[] = another_slice[];` replaces all elements of `slice` with 
copies of `another_slice`'s elements.



  In my specific case, I was using []. Is

waste[] = waste[0..$-1];

even semantically meaningful?  Because the LDC compiler had no problem 
compiling it.


It's equivalent to this:


waste[0] = waste[0..$-1][0];
waste[1] = waste[0..$-1][1];
...
waste[waste.length - 2] = waste[0..$-1][waste.length - 2];
waste[waste.length - 1] = waste[0..$-1][waste.length - 1];


So it basically does nothing. It just copies `waste`'s elements over 
themselves.


Except that the last line makes an out-of-bounds access. That's an error 
that may be detected during compilation or at run time. Or if you're 
telling the compiler to optimize too aggressively, it might go unnoticed.


Re: Looking for a Simple Doubly Linked List Implementation

2019-09-21 Thread ag0aep6g via Digitalmars-d-learn

On 21.09.19 10:34, Ron Tarrant wrote:

Here's a question for the room:

Does a doubly-linked list always have to be done with structs? Can it be 
classes instead? (Maybe that's why I can't get it to work, because I've 
been trying to make an OOP version?)


It can be done with classes.

When I run the following code, it gets through creating the list head 
and the first node, then seems to get stuck in an infinite loop. Here's 
the code:

[...]

class Tab
{

[...]

 Tab* _prev = null, _next = null;

[...]

 Tab* getNext()

[...]

 Tab* getPrev()

[...]

 void setNext(Tab* tab)

[...]

 void setPrev(Tab* tab)

[...]

} // class Tab


Your mistake is that you're using pointers. `Tab` is a class. That means 
values of the type are already references. There is no need for `Tab*`. 
Just use `Tab` wherever you have `Tab*` now, and get rid of any addr-ofs 
(``) and dereferendces (`*bar`) you have.


Re: segmentation fault when running void main() {}

2019-09-18 Thread ag0aep6g via Digitalmars-d-learn

On 17.09.19 20:03, berni wrote:
I'm trying to install D on my old 32-bit machine (debian stable). First 
I tried to install a precompiled version and now I followed [1]. In both 
cases, I always get a segmentation fault when I try to run a compiled 
program.


You're probably hitting this issue:
https://issues.dlang.org/show_bug.cgi?id=19116


Re: getting rid of immutable (or const)

2019-09-05 Thread ag0aep6g via Digitalmars-d-learn

On 05.09.19 21:51, berni wrote:

void main()
{
    int[int] a;

    immutable int b = 17;
    a[1] = b;  // <-- expecting error here
    const oldPointer = (1 in a);
    immutable int c = 10;
    a[1] = c;
    assert(oldPointer is (1 in a));

    Point[int] d;

    immutable Point e = Point(17);
    d[1] = e;   // <-- but error is here
}

struct Point
{
    immutable int x;
}


What's the difference? I can put an immutable int in an AA and I can 
overwrite it (pointer is still the same),


You're not putting an immutable int into an AA. You're copying the value 
of an immutable int to a mutable one.


but I can't do that with a 
struct, having an immutable member. When I remove that immutable inside 
of the struct it works. ?!?


`Point` is effectively the same as `immutable long`. A better simile 
would be this: `immutable(int)[int] a; a[1] = 17;`. And now you get the 
same error. You can't overwrite the element, because its immutable.


You could argue that there is no element before assigning (initializing) 
`d[1]` for the first time. So the assignment should go through the first 
time, and it should only be an error when you try to write a second 
time. But figuring that out mechanically is hard, and DMD isn't smart 
enough to do it. So, to be on the safe side, it just says that you can't 
do that at all.


Re: Why is sformat and formattedWrite (appender) allocating GC mem here?

2019-09-03 Thread ag0aep6g via Digitalmars-d-learn

On 03.09.19 16:03, James Blachly wrote:
For my own learning, why was a unittest to ensure no GC added to sformat 
instead of a @nogc annotation?


`sformat` uses the GC less now, but it's not @nogc. It can still throw 
GC-allocated exceptions, e.g. when the arguments don't match the format 
string.


Re: Why is sformat and formattedWrite (appender) allocating GC mem here?

2019-08-31 Thread ag0aep6g via Digitalmars-d-learn

On 31.08.19 14:07, cc wrote:
I'm guessing it's allocating a string first to write the contents 
of the array and then inserting that string into the buffer I supplied.  
Is there no way to have it skip this step and just write each element 
(plus the joining punctuation, etc) directly into the buffer?


`formatElement` does something like that. It writes the string into a 
temporary buffer while looking for invalid Unicode. When it finds some, 
the temporary is discarded and the whole string is formatted 
differently. When the string is a-ok, the data is copied over to the 
actual destination.


I'm not sure if that's the best approach, though. The temporary buffer 
and the string copy are costly.


There is also a closure being allocated for no reason in `sformat` 
itself. The compiler isn't smart enough to see that it's not really needed.


I've made a pull request to get rid of those allocations:
https://github.com/dlang/phobos/pull/7163


Re: += on associative arrays leads to surprising result

2019-08-27 Thread ag0aep6g via Digitalmars-d-learn

On 27.08.19 18:12, berni wrote:

import std.stdio;

void main()
{
    real[int] a;
    a[0] += 100;
    writeln(a);
}


results (independed of the used compiler) in


[0:100]


I was a little bit surprised, because a[0] += 100 should be the same as 
a[0] = a[0]+100, which leads to a range violation error. Furthermore, as 
we work with real, I'd expected the result to be NaN...


Is this a bug? I ask, because it would be quite convenient to use it the 
way it works now.


For what it's worth, it's in Bugzilla:
https://issues.dlang.org/show_bug.cgi?id=4463


Re: Template specialized functions creating runtime instructions?

2019-08-20 Thread ag0aep6g via Digitalmars-d-learn

On 21.08.19 01:48, ads wrote:

This piece of code creates a fizzbuzz string with template parameters.

auto fizzbuzz(uint N)() {
 string accumulate;
 return fizzbuzz!N(accumulate);
}

auto fizzbuzz(uint N)(ref string result) if (N % 3 && N % 5) {
 import std.conv : to;

 result ~= N.to!string ~ "\n";
 return fizzbuzz!(N - 1)(result);
}

[...]

void main() {
 import std.stdio : writeln;

 fizzbuzz!50().writeln();
}


https://godbolt.org/z/hWENgc

In the generated assembly, it looks like it is creating a lot of runtime 
instructions, contrary to my belief that templated codes are purely 
compile-time. I was expecting that the compiler would deduce the 
fizzbuzz string until 50 in compile-time and just print it in the 
run-time. Why is this not the case?


What you have there are function templates. You're generating functions 
at compile time, and then you're calling those generated functions at 
run time.


To do it all at compile time, you can skip the "functions" part and 
generate the result directly:


template fizzbuzz(uint N) if (N % 3 && N % 5)
{
import std.conv : to;
enum fizzbuzz = N.to!string ~ "\n" ~ fizzbuzz!(N - 1);
}
/* ... etc ... */

You won't be able to use an accumulator, because mutation like that 
doesn't mix with templates.


Alternatively, you can skip the "templates" part and call normal 
functions at compile time (CTFE):


auto fizzbuzz(uint N)
{
string accumulate;
return fizzbuzz(N, accumulate);
}
auto fizzbuzz(uint N, ref string result)
{
import std.conv : to;
if (N % 3 && N % 5) result ~= N.to!string ~ "\n";
/* ... etc ... */
}
void main()
{
import std.stdio : writeln;
enum fz = fizzbuzz(50);
writeln(fz);
}


Re: filtering a row of a jagged array

2019-08-11 Thread ag0aep6g via Digitalmars-d-learn

On 11.08.19 18:11, DanielG wrote:

auto x = whatever[2].filter(x => x > 7); // error


You just forgot an exclamation mark here.

auto x = whatever[2].filter!(x => x > 7); // works


Re: Private variables accessible from outside class

2019-08-08 Thread ag0aep6g via Digitalmars-d-learn

On 08.08.19 18:03, Drobet wrote:

Then why does it in the tour say that it can only be "seen by Integer"?
https://tour.dlang.org/tour/en/basics/classes


That's an error in the tour.


Re: Why does choose not work here

2019-08-01 Thread ag0aep6g via Digitalmars-d-learn

On 01.08.19 22:23, Matt wrote:
Version 4 does not work when PairedA.previous is null. I'd love to 
understand why.



[...]


auto myFilter(R1, R2)(R1 a, R2 b)
{
 import std.algorithm : filter, canFind;
 return a.filter!(c => b.canFind(c));
}

struct A
{
 uint[] starts, stops;

 import std.range : ForwardRange, inputRangeObject;
 import std.typecons : Tuple;
 ForwardRange!(Tuple!(uint,uint)) intervalRange() @property
 {
     import std.algorithm : map;
     import std.range : zip;
     import std.typecons : tuple;
     return zip(starts,stops).map!(a => 
tuple(a[0],a[1])).inputRangeObject;

 }
}

struct PairedA
{

[...]

 //version 4
 auto uniqIntervals() @property
 {
     import std.range : choose;
     import std.algorithm : filter, canFind;
     return choose(previous is null,
     primary.intervalRange,
     primary.intervalRange
     .myFilter(previous.intervalRange));
 }

 A primary;
 A* previous;
}


`choose`'s parameters aren't lazy. So the second argument is evaluated 
even when `previous is null`. That means `intervalRange` is called on a 
null `previous`. And that fails, of course, because `intervalRange` 
can't access `starts` or `stops` when `this` is null.


Re: Why in Phobos is empty() sometimes const and sometimes not

2019-07-29 Thread ag0aep6g via Digitalmars-d-learn

On 29.07.19 21:35, H. S. Teoh wrote:

Generally, the idiom is to let the compiler do attribute inference by
templatizing your code and not writing any explicit attributes, then use
unittests to ensure that instantiations of the range that ought to have
certain attributes actually have those attributes.  For example, instead
of writing:

struct MyRange(R) {
...
@property bool empty() const { ... }
...
}

write instead:

struct MyRange(R) {
...
// No attributes: compiler does inference
@property bool empty() { ... }
...
}

// unittest ensures .empty is callable with const object.
unittest {
const rr = MyRange!(const(Range))(...);
assert(rr.empty); // will fail compilation if .empty is 
non-const
}

The unittest tests that a specific instantiation of MyRange has const
.empty. It's still possible to use MyRange with a range that has
non-const .empty, but this unittest ensures that the non-const-ness
wasn't introduced by the implementation of MyRange itself, but only
comes from the template argument.


But const isn't inferred.


struct MyRange()
{
@property bool empty() { return true; }
}
void main()
{
pragma(msg, typeof(!().empty));
/* Prints: "bool function() pure nothrow @nogc @property @safe"
Note: no const. */
const MyRange!() r;
assert(r.empty); /* fails compilation */
}



Re: __stdin.d(2): Error: found End of File when expecting }

2019-07-17 Thread ag0aep6g via Digitalmars-d-learn

On 17.07.19 21:05, Andre Pany wrote:


```
#!/bin/bash

text="
import std;

void main()
{
     while(true)
     {
     string enemy1 = readln().strip;
     int dist1 = to!int(readln().strip);

     string enemy2 = readln().strip;
     int dist2 = to!int(readln().strip);

     // Write an action using writeln()
     writeln(dist1 > dist2 ? enemy2 : enemy1);
     // Enter the code here
     }
}"

curl -fsS https://dlang.org/install.sh | bash -s dmd-2.087.0
source ~/dlang/dmd-2.087.0/activate
echo $text | dmd -
```

what is here wrong?


Check out what `echo $text` prints:


import std; void main() { while(true) { string enemy1 = readln().strip; 
int dist1 = to!int(readln().strip); string enemy2 = readln().strip; int 
dist2 = to!int(readln().strip); // Write an action using writeln() 
writeln(dist1 > dist2 ? enemy2 : enemy1); // Enter the code here } }



Note that it's all on one line. And remember that a "//"-style comment 
spans the rest of the line.


That's right. Everything after the first "//" is now part of the 
comment, all the way to the last closing brace. Obviously, that's not 
valid code anymore.


Try using double quotes around $text:

echo "$text" | dmd -


Re: q about slices, strings

2019-07-13 Thread ag0aep6g via Digitalmars-d-learn

On 13.07.19 22:35, Kevin Bailey wrote:

     int[char[2]] aa;
     auto arr = "ABBBA";

     foreach (i; 0 .. arr.length - 1)
     aa[arr[i .. $][0 .. 2]]++;

which I changed to:

     aa[arr[i .. i+2][0 .. 2]]++;

in the hopes of only doing:

     aa[arr[i .. i+2]]++;

The question is: Why is the [0..2] still necessary?


[...]


So why isn't arr[i .. i+2] convertible? Is dmd behind the spec here?


Looks like it. It works in the most basic context:

char[2] sa = arr[i .. i + 2];

And it works in the AA context when you use the most basic kind of 
expression:


aa[arr[0 .. 2]]++;

So as far as I can tell, it's just a bug that more complex expressions 
fail in more complex contexts. It should work the same.


Re: Trying to alias this a grapheme range + making it a forward range

2019-07-08 Thread ag0aep6g via Digitalmars-d-learn

On 08.07.19 23:55, aliak wrote:

struct ustring {
     string data;
     this(string data) {
     this.data = data;
     }
     auto get() {
     static struct Range {
     typeof(string.init.byGrapheme) source;
     bool empty() { return source.empty; }
     void popFront() { source.popFront; }
     auto front() { return source.front[]; }
     auto save() { return this; };
     }
     return Range(this.data.byGrapheme);
     }
     alias get this;
}

But I keep on ending up with a UTFException: "Encoding an invalid code 
point in UTF-8" with code like:


writeln("hello".ustring);


`source.front` is a temporary `Grapheme` and you're calling `opSlice` on 
it. The documentation for `Grapheme.opSlice` warns: "Invalidates when 
this Grapheme leaves the scope, attempts to use it then would lead to 
memory corruption." [1]


So you can't return `source.front[]` from your `front`. You'll have to 
store the current `front` in your struct, I guess.


Also, returning a fresh range on every `alias this` call is asking for 
trouble. This is an infinite loop:


auto u = "hello".ustring;
while (!u.empty) u.popFront();

because `u.empty` and `u.popFront` are called on fresh, non-empty, 
independent ranges.



Problem 2:

How can I get the aliased ustring type to behave as a ForwardRange? If I 
add the save method to the voldermort range type, the 
isForwardRange!ustring fails because the requirement on isForwardRange 
checks to see if save returns the same type it's called on. Which is not 
the case here since typeof(ustring.save) == ustring.get.Range). But 
nontheless does have a save method.


You must provide a `save` that returns a `ustring`. There's no way 
around it.


Maybe make `ustring` itself the range. In the code you've shown, the 
`alias this` only seems to make everything more complicated. But you 
might have good reasons for it, of course.


By the way, your're not calling `source.save` in `Range.save`. You're 
just copying `source`. I don't know if that's effectively the same, and 
even if it is, I'd advise to call `.save` explicitly. Better safe than 
sorry.



[1] https://dlang.org/phobos/std_uni.html#.Grapheme.opSlice


Re: Why are immutable array literals heap allocated?

2019-07-06 Thread ag0aep6g via Digitalmars-d-learn

On 06.07.19 01:12, Patrick Schluter wrote:

On Friday, 5 July 2019 at 23:08:04 UTC, Patrick Schluter wrote:

On Thursday, 4 July 2019 at 10:56:50 UTC, Nick Treleaven wrote:

immutable(int[]) f() @nogc {
    return [1,2];
}

[...]


and it cannot optimize it away because it doesn't know what the caller 
want to do with it. It might in another module invoke it and modify it, 
the compiler cannot tell. auto a=f(); a[0]++;


f returns immutable. typeof(a) is immutable(int[]). You can't do a[0]++.


Re: Finding Max Value of Column in Multi-Dimesional Array

2019-07-05 Thread ag0aep6g via Digitalmars-d-learn

On 05.07.19 20:49, Samir wrote:
As a follow-on to my earlier question, is there a way to pass a variable 
to the `map` function that specifies the column, rather than hard-coding 
it?  I'm thinking of something like:


p.map!("a[column]").maxElement.writeln;


You can't do that with the string style, because the string is turned 
into a function inside of `map`. Your `column` isn't visible there.


It works when you pass an actual callable instead, e.g. a lambda:

p.map!(a => a[column]).maxElement.writeln;


Re: Associative Array & different template types

2019-07-03 Thread ag0aep6g via Digitalmars-d-learn

On 03.07.19 20:20, Robert M. Münch wrote:
So, I need to carry around the object from which a delegate was created 
from because it's not possible to query the delegate for the object 
later somewhere else in the code.


It is possible to get the context object out of a delegate:


class C { void method() {} }
void main()
{
auto c = new C;
void delegate() dg = 
assert(cast(C) dg.ptr is c); /* passes */
}


You just have to know (or carry around) the type so that you can cast 
correctly.


[...]

myObject[string] myObjectArray;

auto mo1 = makeMyStruct!myClassA(mcA, ); // mo1 = myObject
auto mo2 = makeMyStruct!myClassB(mcB, ); // mo2 = myObject

myObjectArray["1"] = mo1;
myObjectArray["2"] = mo2;

assert(mcA == mo1._context)
assert(mcA == myObjectArray["1"]._context)


class MyClassA { void myClassFunc() {} }
class MyClassB { void myClassFunc() {} }

void main()
{
void delegate()[string] myDelegateArray;

auto mcA = new MyClassA;
auto mcB = new MyClassB;

auto dg1 = 
auto dg2 = 

myDelegateArray["1"] = dg1;
myDelegateArray["2"] = dg2;

assert(mcA is cast(MyClassA) dg1.ptr); /* passes */
assert(mcA is cast(MyClassA) myDelegateArray["1"].ptr); /* passes */

/* When void* is good enough, you can use .ptr without a cast: */
assert(dg2.ptr is myDelegateArray["2"].ptr); /* passes */
}


Re: Using scanw Ncurses in D lang

2019-06-15 Thread ag0aep6g via Digitalmars-d-learn

On 15.06.19 23:20, Gabol wrote:

example: scanw("% i", & number); // The compiler accuses error.

Error: function deimos.ncurses.curses.scanw(char* fmt, ...) is not 
callable using argument types (string, int*)
source/app.d(8,14):    cannot pass argument "0" of type string to 
parameter char* fmt

/usr/bin/dmd failed with exit code 1.


Off topic:

The string literal in the error message is wrong. It's "0" when it 
should be "% i". I've made a PR to fix it:

https://github.com/dlang/dmd/pull/10040


Re: Delegate / Error: cannot implicitly convert expression...

2019-06-15 Thread ag0aep6g via Digitalmars-d-learn

On Saturday, 15 June 2019 at 17:24:45 UTC, user1234 wrote:

---
void foo(){writeln(__PRETTY_FUNCTION__);}

void main(string[] args)
{
void delegate() dg;
dg.funcptr = 
dg.ptr = null; // usually a "this" or a frame address
dg();
}
---

because dg.ptr would be used to retrieve the offset of the 
locals variable used in the parent stack or the address of a 
class instance (the this). But this is not required at all 
here. The opposite way would lead to various access violation.


That only works because foo doesn't have any parameters. When you 
add even just one, things will go wrong.


Re: Function parameters UDAs

2019-06-10 Thread ag0aep6g via Digitalmars-d-learn

On 11.06.19 01:12, Johannes Loher wrote:
I would like to iterate over all parameters of a function using static 
foreach and then process each parameter's UDAs. But by using static 
foreach on the parameter tuple, slicing it is not possible anymore, so 
the suggested workaround does not work in this case :(


The workaround is to work with 1-length slices of your parameter 
sequence instead of elements. You can still do that. You just can't 
`foreach` over the parameters directly. Instead, iterate with an index 
and use it to get slices:


-
import std;

struct Test
{}

void foo(@(1) Test x, @(2) @(3) float y)
{
}

void main()
{
alias Params = Parameters!foo;
pragma(msg, Params);
static foreach(i; 0 .. Params.length)
{{
alias P = Params[i .. i + 1];
pragma(msg, P);
static foreach(uda; __traits(getAttributes, P))
{
pragma(msg, uda);
}
}}
}


Prints:


(@(1) Test, @(tuple(2), tuple(3)) float)
(@(1) Test)
1
(@(tuple(2), tuple(3)) float)
2
3



Re: Error: char 0x200b not allowed in identifier

2019-06-03 Thread ag0aep6g via Digitalmars-d-learn

On 03.06.19 15:37, zoujiaqing wrote:

Error for code:
source/hunt/xml/Element.d(12,13): Error: char 0x200b not allowed in 
identifier


U+200B is: ZERO WIDTH SPACE. Somehow you got that invisible character 
into your code. You have to get rid of it.


To do it manually, navigate to the locations the compiler gives you and 
find the spot where the cursor seems to get stuck for one key press. 
That's where a zero width space is.


You can also open the file in a different non-Unicode encoding. The zero 
width spaces should stick out as non-ASCII symbols.


Or you could write a program that goes over the file and filters the 
zero width spaces out.


Or just re-write whole lines or the whole file by hand.


Re: How to create an overwriteable struct that is always const?

2019-06-02 Thread ag0aep6g via Digitalmars-d-learn

On 02.06.19 04:22, David Zhang wrote:

On Saturday, 1 June 2019 at 13:00:50 UTC, ag0aep6g wrote:


How is setting/replacing different from modifying?


e.g.:

     S s;

     this() { s = ...; }

     update(S s) { this.s = s; }

     mod(int i) { s.i = i; } // illegal

Kinda like how strings can be copied and assigned to, but not modified.


The `string` itself can be modified: You can change its length, and you 
can make it refer to other characters. That's modifying.


You can't modify the string's characters, because the string refers to 
them with an `immutable(char)*` pointer. That means the pointer itself 
is mutable (can be modified), but the data it points to is immutable 
(can't be modified).


You can do the same in your struct: `const(char)* pointer;`. Then you 
can modify the pointer but you can't modify the data it points to.


Re: How to create an overwriteable struct that is always const?

2019-06-01 Thread ag0aep6g via Digitalmars-d-learn

On 01.06.19 14:51, David Zhang wrote:

     struct S {
     /*const*/ char* pointer;
     ... other members ...

     this(/*const*/ char* p, ... others ...) {
     pointer = p;
     ...
     }
     }

What I want, is to be able to use `S` in other data structures with the 
following properties checked by the compiler:


  - The variable can be set
  - The variable can be read
  - The variable cannot be modified, only replaced


How is setting/replacing different from modifying?

Is there a type-safe way to do this? If this were a class, I'd try 
std.typecons.Rebindable.


struct S
{
const(char)* pointer;
/* ... */
}


Re: Parameter pack expansion

2019-05-30 Thread ag0aep6g via Digitalmars-d-learn

On 30.05.19 22:20, Tomas wrote:
Surely, there has to be a 
standard function which does exactly(probably better) the same thing as 
what `myMap` does.


Nope.


Re: Is using floating point type for money/currency a good idea?

2019-05-20 Thread ag0aep6g via Digitalmars-d-learn

On 20.05.19 13:47, Josh wrote:
Normally I would say no, no and no.  Rounding issues will kill you every 
time.


And you'd be right.


  However:

import std.stdio;
import std.range;

void main()
{
 foreach (i; iota(1, 1000)) {
     writefln("%f", cast(float) i / 100.0);
 }
}

Doesn't show any rounding issues, but you still might hit them at large 
values...I just remember back in the day having numbers like 
0.199, but maybe that problem has been solved.


That "problem" hasn't been solved. It can't be solved. `1 / 100.0` might 
print as 0.01, but it isn't exactly 0.01. The output is just rounded. If 
you add more decimals (e.g. `writefln("%.20f", ...)`), those niners will 
show up.


Aside from large and small values, you'll also see significant 
(accumulated) rounding error when doing many operations on your numbers. 
For example, if you add 0.1 ten thousand times, you might expect the 
result to be 1000, but with `float` it's not that:


import std.stdio;
void main()
{
float x = 0;
foreach (i; 0 .. 10_000) x += 0.1;
writeln(x); /* Prints "999.903". */
}

What would be safer is to do "fixed point" math, i.e. use an integer and 
when displaying the value convert it to float and divide by 100.  So if 
the user has 50 cents they internal value would be 50, if you give them 
a dollar twenty five (125) then they would have 175, and when you go to 
display it, dividing by 100 will display 1.75.


Yup.

As long as you are not multiplying money by money you will be fine.  50 
cents times 5 is 2.50 (50 * 5 = 250), however 50 cents times 50 cents is 
2500, which makes no sense but so does multiplying money by money...


50 cents times 50 cents is 2500 square cents. Makes perfect sense.


Re: 1 - 17 ms, 553 ╬╝s, and 1 hnsec

2019-05-17 Thread ag0aep6g via Digitalmars-d-learn

On 16.05.19 17:55, Vladimir Panteleev wrote:

On Thursday, 16 May 2019 at 15:52:05 UTC, Steven Schveighoffer wrote:

[...]
The output shouldn't involve the inner workings of the type. It should 
be changed to say 10 ns.


If the output is meant for the developer, then I disagree subjectively, 
as that creates the impression that the lowest resolution or 
representable unit of time is the nanosecond.


If the output is meant for the user, then hectonanoseconds or 
nanoseconds are going to be almost always irrelevant. The duration 
should be formatted appropriately to the use case.




I'd suggest "17 ms, and 553.1µs" for a better default (1 hns is 0.1 µs, 
right?). No weird "hnsecs", no false precision, still all the data that 
is there.


Re: Cast ptr/len to D-style array

2019-05-02 Thread ag0aep6g via Digitalmars-d-learn

On 02.05.19 22:03, James Blachly wrote:

I work a lot with C functions, many of which yield pointer + length.

Is there a way to cast this or materialize a D-style array backed by the 
already allocated data (with length) to avoid copies which slow things 
down?


Just slice the pointer with the length:

int* ptr;
size_t len;
int[] arr = ptr[0 .. len];


Re: dmd -unittest -main -run: undefined reference to `_D1c12__ModuleInfoZ'

2019-05-02 Thread ag0aep6g via Digitalmars-d-learn

On 02.05.19 01:18, kdevel wrote:

Now I have:

a/main.d
a/b/package.d
a/b/c/package.d

b/package.d and c/package.d as before.


For reference, a/b/c/package.d is this:

module c; package import std.file;

And a/b/package.d starts with:

   module b; import c;


a/main.d is

```
import b;

void dummy ()
{
    string s = "test";
    mkdir (s);
}
```

In cwd a/ with

    $ dmd -unittest -main -i -run main.d

I get

    b/package.d(2): Error: module `c` is in file 'c.d' which cannot be read
    import path[0] = /.../dmd2/linux/bin64/../../src/phobos
    import path[1] = /.../dmd2/linux/bin64/../../src/druntime/import

Why does dmd not get it?


If you want c to be part of the package b, you have to state that in the 
module declaration and when importing it.


In c/package.d:

module b.c;

In b/package.d:

import b.c;

Module declarations and imports are always absolute. They're not 
relative to the current package. If you add a new root directory on top, 
you have to adjust those declarations in all files.


I have to supply -I=b explicitly. Which leads 
me to

the actual problem I wanted to post:

    $ dmd -unittest -main -I=b -run main.d
    main.d(6): Error: undefined identifier mkdir


main only imports b. And b doesn't expose mkdir.

You can either import c (or rather b.c) in main, or make b's import of c 
public.


By the way, `package import` seems to work just like `public import`, 
not restricting anything. Looks like a compiler bug.


The problem I see here is that b passes the isolated unittest. But when 
it is used undefined symbols show up. I stumbled over this problem while 
using a project as submodule which uses msgpack-d as its submodule. Only 
if I restrict

the import like in

    import msgpack : unpack, pack;

my submodule's unittest fails right away. My submodule corresponds to 
b/package.d in this thread. I suppose the line


     package import std.file, core.stdc.string;

in msgpack-d's file packer.d causes the export of mkdir. Right?


"Export" in the sense of D identifier visibility, yes.

Note that an "undefined identifier" error is different from one about an 
"undefined reference". The former is the compiler saying it can't find 
the definition of a D identifier. The latter is the linker saying it 
can't find a symbol in the object files.


Re: dmd -unittest -main -run: undefined reference to `_D1c12__ModuleInfoZ'

2019-05-01 Thread ag0aep6g via Digitalmars-d-learn

On 02.05.19 00:25, kdevel wrote:

dmd -unittest -main -run package.d c/package.d


That doesn't compile c/package.d. Everything after `-run package.d` is 
interpreted as an argument to the compiled program.


I.e., that line effectively does this:

dmd -unittest -main package.d
./package c/package.d

You need to put c/package.d before -run:

dmd -unittest -main c/package.d -run package.d

Or use -i so that DMD compiles the imported module automatically:

dmd -unittest -main -i -run package.d


Re: Alias to struct memembers of a function paramater as a shortcut => need this for XYZ of type void*

2019-04-07 Thread ag0aep6g via Digitalmars-d-learn

On 07.04.19 17:36, Robert M. Münch wrote:
The docs state that an alias can either be related to the type or the 
symbol. Hence, in my case I expected it to be the symbol...


The symbol is `X.a`. A field of an instance doesn't make a distinct symbol.


Re: Alias to struct memembers of a function paramater as a shortcut => need this for XYZ of type void*

2019-04-07 Thread ag0aep6g via Digitalmars-d-learn

On 07.04.19 14:23, Robert M. Münch wrote:

struct X {
 TYPE a;
 TYPE b;
}


myFunc(X _struct){
 alias a = _struct.a;

 a = myOtherFunc();
}


X myStruct;

myFun(myStruct);


This gives an error: need this for a of type void*

I don't understand why, because all I want is a shortcut the symbol of 
the parameter.


You can't make an alias to a field of an object. The alias will be made 
in relation to the type instead. (If that makes sense. I'm not sure how 
to phrase it best.)


In code, this:

alias a = _struct.a;

is the exact same as this:

alias a = X.a;

The instance `_struct` is not part of the alias.


Re: alias sequences of sequences

2019-04-07 Thread ag0aep6g via Digitalmars-d-learn

On 07.04.19 06:58, Alex wrote:

Is there any way to get sequences of sequences?

Using RT, I have to use strings

[[`string`, `0`], ...]

when it would be much better to use

[[string, 0], ...]

Ideally it wouldn't add so much overhead that it defeats the purpose.


You can make a template that doesn't expand the sequence automatically, 
and then make a sequence of those:



template Box(stuff ...) { alias contents = stuff; }
import std.meta: AliasSeq;
alias s = AliasSeq!(Box!(string, 0), Box!(int, 42));


Instead of `s[0][0]`, you'd have to write `s[0].contents[0]`. Don't know 
if that's too much overhead.


Re: CTFE & code generators based on PEG grammars?

2019-04-07 Thread ag0aep6g via Digitalmars-d-learn

On 07.04.19 05:32, Alex wrote:

readlin is not a CT function. You misinterpreted what I said.


Yeah, bad example from me. This would probably have been better:


auto v = "foo";
enum y = f(v); /* Error: variable v cannot be read at compile time */


Also, the `readln` example wasn't meant to contradict anything you said. 
The one after it (`auto z = f("foo"); /* not CTFE */`) is supposed to 
clarify your statement that "CTFE [happens] when the inputs are CT". 
It's true that CTFE can only happen when the inputs are known at CT, but 
that alone doesn't force CTFE.


[...]
If you think of it the way I have said and understand what it means then 
it is much easier to understand CTFE because you really are just doing 
"normal" programming of RT functions but you just execute them at CT if 
possible(and the possibility simply is if the inputs are known at CT).


There's that same slight unclarity again. You may have the right 
understanding of CTFE, but your phrasing is a bit misleading. CTFE 
doesn't kick in whenever it's possible to precompute something at CT. It 
only kicks in when the result is required at CT by language rules.


[...]
CTFE programming is RT 
programming but where one can optimize before RT.


Optimization is not the only use for CTFE. It can also be used to 
generate compile-time constants, like lengths for static arrays or D 
code itself that is then mixed in. Can't do that stuff with run-time calls.


Re: CTFE & code generators based on PEG grammars?

2019-04-06 Thread ag0aep6g via Digitalmars-d-learn

On 06.04.19 16:19, Alex wrote:
That is CTFE is CT RTFE where runtime functions are executed at compile 
time when the inputs are CT.


You may have the right idea, but the last part of that sentence is 
wrong/misleading. CTFE happens when the result is required at CT. The 
inputs must be available at CT, but that alone doesn't trigger CTFE.


Examples:


bool f(string s) { return __ctfe; }
void main()
{
import std.stdio: readln;
enum x = f("foo"); /* CTFE */
enum y = f(readln()); /* error, because "readln" can't be CTFEd */
auto z = f("foo"); /* not CTFE */
}



Re: Using opOpAssign, cannot assign sequence

2019-04-05 Thread ag0aep6g via Digitalmars-d-learn

On 05.04.19 16:00, Alex wrote:
I was thinking using tuple would work(of course is longer than Add but 
would allow for a more general approach, it would require automatic 
unpacking though and so doesn't work.


`tuple` works for me:


import std.typecons: tuple;

class X(T ...)
{
void opOpAssign(string op)(T d) {}
}

void main()
{
auto x = new X!(int, float, string);
int a = 42;
float b = 4.2;
string c = "foo";
x += tuple(a, b, c);
}



Re: Wrong initialization of variables

2019-04-01 Thread ag0aep6g via Digitalmars-d-learn

On 01.04.19 18:31, Andrey wrote:
Also with AST switch I get code where there aren't any lines with text 
"bool hasqwerty = false;" or "bool haszaqy = false;". What happens?


Compiler bug. https://issues.dlang.org/show_bug.cgi?id=19479


Re: "if" statement

2019-03-24 Thread ag0aep6g via Digitalmars-d-learn

On 24.03.19 13:45, Francesco Mecca wrote:

```
alias Alg = Algebraic!(int, string);

void main()
{
 int n = 2;
     Alg value;

     value = n == 2 ? 2 : "string";
}
```

The original code used SumType but the effect is the same.

I suppose that I could write the following:

```
     if(n == 2) value = 2;
     else value = "string";
```

Is there a workaround for this that maintains a similar syntactic 
structure?


value = n == 2 ? Alg(2) : Alg("string");


is this behaviour accepted


Yes.

or should the compiler translate the first 
case in the second?


No.


Re: local class instance (at module-level)

2019-03-14 Thread ag0aep6g via Digitalmars-d-learn

On 14.03.19 20:43, Jacob Carlborg wrote:

class C {
     uint i ;
     this (uint i) {
     this.i = i ;
     }

     this (uint i) shared {
     this.i = i ;
     }

     this (uint i) immutable {
     this.i = i ;
     }
}

__gshared c0 = new C(0);
shared c1 = new shared C(1);
immutable c2 = new immutable C(2);

You only need one of the constructors depending on if you want a 
__gshared, shared or immutable variable.


If you make it `pure`, you can use the same constructor in all cases:


class C {
uint i ;
this (uint i) pure {
this.i = i ;
}
}

__gshared c0 = new C(0);
shared c1 = new shared C(1);
immutable c2 = new immutable C(2);



Re: How are (Static) Libraries with Templates Compiled?

2019-03-11 Thread ag0aep6g via Digitalmars-d-learn

On Monday, 11 March 2019 at 19:53:53 UTC, jmh530 wrote:
So what information is in the static library that allows this 
to take place?


None. The information is in in the source or interface file 
(.d/.di). Templates can't be compiled before they're instantiated.


Re: Array of byLineCopy ranges behaves as they are byLine

2019-03-11 Thread ag0aep6g via Digitalmars-d-learn

On Monday, 11 March 2019 at 15:23:53 UTC, HaraldZealot wrote:

```d
File[] files;
foreach(filename; args[1 .. $])
{
files ~= File(filename, "r");
}

auto ranges = files.map!(a => a.byLineCopy);

writeln(ranges[0].front);
writeln(ranges[0].front);
writeln(ranges[0].front);
```
produces
```
1
2
3
```

[...]

What I'm doing wrong with `map`? Or is this a bug?


`map` is lazy in the sense that it (re-)evaluates the given 
function whenever you access an element. That means you're 
calling `byLineCopy` three times on the same file. Your code 
effectively does this:


writeln(files[0].byLineCopy.front);
writeln(files[0].byLineCopy.front);
writeln(files[0].byLineCopy.front);

The range created by `byLineCopy` immediately reads a line from 
the file to populate its `front`. So you're reading three lines 
from the file.


Strictly speaking, I don't think any of this qualifies as a bug. 
`map`'s behavior might be surprising, but it's deliberate, as far 
as I know.


To avoid the re-evaluation, assign `ranges[0]` to a variable 
before using it:


auto lines = ranges[0];
writeln(lines.front);
writeln(lines.front);
writeln(lines.front);

That should print the same line three times.


Re: 2 class issues

2019-03-07 Thread ag0aep6g via Digitalmars-d-learn

On 07.03.19 11:38, spir wrote:
-1- How to enforce that subclasses implement given methods without using 
"abstract", which seems to make the whole class abstract?


Not, as far as I can tell. You can't force derived classes to override 
an existing implementation. And you can't omit the implementation 
without making the class abstract.


-2- How to have "constant" (predefined) class instances at the 
module-level?


Just like so?

const o = new Object; /* works for me */


The compiler requires a "static this ()".


For what code does it say that?

What does this 
actually mean (for a constructor)? What are the consequences, for either 
my code or client code? (The doc on the topic [2] is rather obscure for 
me, and I could not find better elsewhere.)


I'm also bluffed by "Static constructors have empty parameter lists." 
Does this mean I should manually fill the fields? (not a big deal, but 
why???) This may give:

     // Predefined pseudo-pattern "End-of-Text":
     auto EoT = new Pattern() ;   // ???
     EoT.name = "EoT" ;

     // Unique lexeme "end-of-text":
     auto eot = new Lexeme() ;   // ???
     eot.patname = "EoT" ;
     eot.slice = null ;
     eot.index = uint.max ;
Then, why have a constructor at all? This would also prevent me from 
making classes immutable, while conceptually all are immutable... (no 
reason for a pattern or a lexeme to change)


You're misunderstanding the nature of static constructors.

Static constructors are a special kind of function that runs once at the 
beginning of the program/thread, automatically. They're not constructors 
for static objects. You can't call static constructors from your code. 
`new Foo` calls a (normal) constructor; doesn't matter if you're 
creating a dynamic instance or a static one.


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

2019-02-27 Thread ag0aep6g via Digitalmars-d-learn

On 27.02.19 19:10, Dukc wrote:
I tested a bit, and it appears that attribute inference is not done at 
all for templates inside structs -the attribute need not be a delegate:


struct S
     {
     static int fImpl(Ret)() { return Ret.init; }

     pragma(msg, __traits(getFunctionAttributes, fImpl!int)); // 
still tells us: `f` is @system

     }

void main(){}

A bug, unless I'm overlooking something.


It's not quite as simple as that. When you put the pragma in a function, 
the inferred attributes show up:



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

pragma(msg, __traits(getFunctionAttributes, S.f!())); /* @system */

void g()
{
pragma(msg, __traits(getFunctionAttributes, S.f!()));
/* Same line now says @safe. */
}


But I agree that this can't be right.


Re: template alias argument accepts only class/interface types.

2019-02-23 Thread ag0aep6g via Digitalmars-d-learn

On 23.02.19 23:30, Alexandru Ermicioi wrote:
According to 
https://dlang.org/spec/template.html#TemplateAliasParameter, simple 
types and arrays are excluded from the list of supported "alias X" 
arguments. I'm wondering why do we have such limitation? Is there any 
reasoning at limiting primitive types and arrays?


As far as I'm aware, there is no good reason. There's a Bugzilla issue 
for it that also gives some history:


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

Apparently even Walter has been convinced by now that it's a silly 
limitation which should be lifted.


Re: Generalizing over function pointers and delegates

2019-02-15 Thread ag0aep6g via Digitalmars-d-learn

On 15.02.19 15:20, Bastiaan Veelo wrote:
Exploiting this, it is possible to explicitly convert a function pointer 
into a delegate [2]:

```
Ret delegate(Args args) fun_to_dlg(Ret, Args...)(Ret function(Args args) 
fun)

{
     Ret delegate(Args) dlg;
     dlg.funcptr = fun;
     return dlg;
}
```

[...]
This may be preferable to the overload, depending on the number of calls 
like this. But since this is allowed and working, why can't it be done 
automatically? Or, when implicit conversion is dangerous, why doesn't a 
cast exist to the effect of my template? Have I overlooked an easier way 
of doing this?


Your fun_to_dlg fails when the function has parameters.

As far as I see, it would be possible make the conversion would work by 
changing how a delegate's context is passed [1]. But I didn't pursue 
that idea further, and no one else picked it up either.


[1] https://forum.dlang.org/post/ofc0lj$2u4h$1...@digitalmars.com


Re: What is the Utility of Parent Class Method Hiding in Inheritance?

2019-01-14 Thread ag0aep6g via Digitalmars-d-learn

On 14.01.19 10:10, Vijay Nayar wrote:
After a bit of reading, I understood the rule and how it works, but what 
I'm missing is the "why".  Why is it desirable to hide methods from a 
parent class which have the same name (but different arguments) as a 
method in a class?


https://dlang.org/articles/hijack.html#derived-class-members


Re: Dlang tour - Unittesting example

2018-10-02 Thread ag0aep6g via Digitalmars-d-learn

On 10/02/2018 03:24 PM, Basile B. wrote:

The problem is the NaN madness.
Since several values are NaN there's this strange stuff:

void main()
{
     import std.stdio;
     import std.math : isNaN;
     double d;

     writeln(d.init);    // nan
     writeln(d); // nan
     writeln(d.nan); // nan

     assert(d.isNaN);
     assert(d == d.nan);  // fails
     assert(d == d.init); // fails
}

the last assert is just crazy.


NaN simply isn't equal to itself. Has nothing to do with there being 
multiple NaNs. `d == d`, `double.nan == double.nan`, `double.init == 
double.init` are all false, too.


  1   2   3   4   5   6   7   >