Re: How to print unicode characters (no library)?

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

On 27.12.21 15:23, Adam D Ruppe wrote:

Let's look at:

"Hello \n";

[...]
Finally, there's "string", which is utf-8, meaning each element is 8 
bits, but again, there is a buffer you need to build up to get the code 
points you feed into that VM.

[...]
H, e, l, l, o, , MORE elements>, , 
, final work-in-progress element>, 

[...]
Notice how each element here told you how many elements are left. This 
is encoded into the bit pattern and is part of why it took 4 elements 
instead of just three; there's some error-checking redundancy in there. 
This is a nice part of the design allowing you to validate a utf-8 
stream more reliably and even recover if you jumped somewhere in the 
middle of a multi-byte sequence.


It's actually just the first byte that tells you how many are in the 
sequence. The continuation bytes don't have redundancies for that.


To recover from the middle of a sequence, you just skip the orphaned 
continuation bytes one at a time.


Re: Double bracket "{{" for scoping static foreach is no longer part of D

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

On 22.12.21 17:01, rikki cattermole wrote:
Anyway, AliasAssign has nothing to do with this. This "trick" creates a 
closure aka ``() { ... }``. Thats all its doing.


 From the AST dump:

```
import object;
import std;
void main()
{
 {
     string str = "Abc";
     writeln("Hello D ", str, 2098L);
 }
 {
     string str = "def";
     writeln("Hello D ", str, 2098L);
 }
 return 0;
}
```


In this context, `{ ... }` is not the same as `() { ... }`.

Also, `() { ... }` is not a closure, and does not necessarily involve a 
closure.


Just a scope:


import std.stdio;
void main()
{
{
string str = "Abc";
writeln("Hello D ", str, 2098L);
}
}


An immediately called function literal:


import std.stdio;
void main()
{
() {
string str = "Abc";
writeln("Hello D ", str, 2098L);
} ();
}


Returning a closure:


import std.stdio;
void main() { f("Abc")(); }
auto f(string str)
{
return { writeln("Hello D ", str, 2098L); };
}



Re: A debug class has started

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

On 13.12.21 12:09, drug wrote:
That's because `str` is initialized by a literal and you can not change 
it by definition. When you call `toStringz` it duplicates that literal 
(adding terminating zero at the end) and the duplicate is mutable. I 
would recommend do not use `toStringz` and just make duplicate of the 
literal - https://run.dlang.io/is/vaosW0


From the link:


string str = "abc;def;ab".dup; // allocates the string in the heap
char* w = cast(char*)str;
writeln(replaceChar(w, str.length, ';', 'X'));


That still has undefined behavior. You cannot mutate the characters in a 
`string`. It doesn't matter if it came from a literal or `.dup`. Use 
`char[]` instead of `string`.


Re: How to test if a string is pointing into read-only memory?

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

On 12.10.21 10:19, jfondren wrote:

```d
/+ Unfortunately, this isn't reliable.
  We could make this work if string literals are put
  in read-only memory and we test if s[] is pointing into
  that.

  /* Peek past end of s[], if it's 0, no conversion necessary.
  * Note that the compiler will put a 0 past the end of static
  * strings, and the storage allocator will put a 0 past the end
  * of newly allocated char[]'s.
  */
  char* p = [0] + s.length;
  if (*p == 0)
  return s;
  +/
```

[...]
As for whether it's a necessarily a good idea to patch toStringz, I'd 
worry that


1. someone will slice a string literal and pass the test while not 
having NUL where it's expected


The (commented-out) code checks if the NUL is there. Just make sure that 
it's also read-only.


2. people are probably relying by now on toStringz always allocating, to 
e.g. safely cast immutable off the result.


It doesn't matter if the result is freshly allocated. Casting away 
immutable is only allowed as long as you don't use it to actually change 
the data (i.e. it remains de-facto immutable).


Re: Is this a compiler aliasing bug?

2021-09-17 Thread ag0aep6g via Digitalmars-d-learn

On 17.09.21 11:44, Chris Katko wrote:

bool is_colliding_with(drawable_object_t obj) //was a class member
 {

[...]

 alias x2 = obj.x;
 alias y2 = obj.y;
 alias w2 = obj.w;
 alias h2 = obj.h;

[...]

     }


Those aliases don't work like you want them to. You can't have an alias 
to an object's field. What you get is an alias to the symbol in the 
class. I.e., you get this:


alias x2 = typeof(obj).x;

And when you use that in a method, it becomes `this.x`. `obj` is 
completely forgotten.


I my opinion, `alias x2 = obj.x` should be an error, but I'm not sure if 
it's considered a bug.


Re: Merge 2 structs together (into a single struct)?

2021-09-16 Thread ag0aep6g via Digitalmars-d-learn

On 16.09.21 22:53, jfondren wrote:

string joinstruct(A, B)(string name) {
     string s = "struct " ~ name ~ " {";
     alias memA = __traits(allMembers, A);
     alias memB = __traits(allMembers, B);
     alias initA = A.init.tupleof;
     alias initB = B.init.tupleof;
     static foreach (i; 0 .. memA.length) {
     s ~= typeof(__traits(getMember, A, memA[i])).stringof;
     s ~= " ";
     s ~= memA[i];
     s ~= " = ";
     s ~= initA[i].stringof;
     s ~= ";\n";
     }
     static foreach (i; 0 .. memB.length) {
     s ~= typeof(__traits(getMember, B, memB[i])).stringof;
     s ~= " ";
     s ~= memB[i];
     s ~= " = ";
     s ~= initB[i].stringof;
     s ~= ";\n";
     }
     s ~= "}";
     return s;
}


As a rule of thumb, don't use `stringof` for string mixins. There's 
usually a better way.


In this case, if you make `joinstruct` a struct template, you can use 
the types and init values of the fields directly, without converting 
them to strings and back. Only the names need to be mixed in as strings.



struct JoinStruct(Structs ...)
{
static foreach (S; Structs)
{
static foreach (i, alias f; S.tupleof)
{
mixin("typeof(f) ", __traits(identifier, f),
" = S.init.tupleof[i];");
}
}
}



Re: Question on Immutability

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

On 31.08.21 02:50, Mike Parker wrote:
Member functions marked as immutable can be called on both mutable and 
immutable instances.


That's not true.


Re: compile time compression for associatve array literal

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

On 23.08.21 08:14, Brian Tiffin wrote:
 From ~~a~~ little reading, it seems associative array literal 
initialization is still pending for global scope, but allowed in a 
module constructor?  *If I understood the skimming surface reading so far*.


```d
immutable string[string] things;
static (this) {
    things = ["key1": "value 1", "key2": "value 2"];
}
```


(Typo: It's `static this()`.)

Is there a magic incantation that could convert the values to a 
`std.zlib.compress`ed ubyte array, at compile time?  So the object code 
gets keys:compvals instead of the full string value?


There's a big roadblock: std.zlib.compress cannot go through CTFE, 
because the source code of zlib isn't available to the compiler; it's 
not even D code.


Maybe there's a CTFE-able compression library on dub. If not, you can 
write your own function and run that through CTFE. Example with simple 
run-length encoding:



uint[] my_compress(string s)
{
import std.algorithm: group;
import std.string: representation;
uint[] compressed;
foreach (c_n; group(s.representation))
{
compressed ~= [c_n[0], c_n[1]];
}
return compressed;
}

string my_uncompress(const(uint)[] compressed)
{
import std.conv: to;
string uncompressed = "";
for (; compressed.length >= 2; compressed = compressed[2 .. $])
{
foreach (i; 0 .. compressed[1])
{
uncompressed ~= compressed[0].to!char;
}
}
return uncompressed;
}

import std.array: replicate;

/* CTFE compression: */
enum compressed = my_compress("f" ~ "o".replicate(100_000) ~ "bar");

immutable string[string] things;
shared static this()
{
/* Runtime decompression: */
things = ["key1": my_uncompress(compressed)];
}


If you compile that, the object file should be far smaller than 100,000 
bytes, thanks to the compression.


[...]

I'm not sure about

a) if code in a module constructor is even a candidate for CTFE?


The word "candidate" might indicate a common misunderstanding of CTFE. 
CTFE doesn't look for candidates. It's not an optimization. The language 
dictates which values go through CTFE.


In a way, static constructors are the opposite of CTFE. Initializers in 
module scope do go through CTFE. When you have code that you cannot (or 
don't want to) put through CTFE, you put it in a static constructor.


You can still trigger CTFE within a static constructor by other means 
(e.g., `enum`), but the static constructor itself is just another 
function as far as CTFE is concerned.


b) what a cast might look like to get a `q"DELIM ... DELIM"` delimited 
string for use as input to std.zlib.compress?


A cast to get a string literal? That doesn't make sense.

You might be looking for `import("some_file")`. That gives you the 
contents of a file as a string. You can then run that string through 
your compression function in CTFE, put the resulting compressed data 
into the object file, and decompress it at runtime (like the example 
above does).


Re: Union member positions?

2021-08-17 Thread ag0aep6g via Digitalmars-d-learn

On 17.08.21 15:46, z wrote:
Is it possible to set a "position" on a union member? or is there is a 
language-integrated equivalent?
For example, to get access to each byte in an unsigned integer while 
still supporting the original type.

```D
///a single uint that would be accessed as two ushort, or four separate 
ubyte

union UnionExample{
uint EAX;

//upper
ushort EAHX;

ubyte EAHH;
ubyte EAHL;

//lower
ushort EALX;

ubyte EALH;
ubyte EALL;
}
```
Thanks.


union UnionExample
{
uint EAX;
struct
{
union // upper
{
ushort EAHX;
struct
{
ubyte EAHH;
ubyte EAHL;
}
}
union // lower
{
ushort EALX;
struct
{
ubyte EALH;
ubyte EALL;
}
}
}
}


Re: Getting a working example of opIndexAssign using opSlice ... have troubles ...

2021-08-15 Thread ag0aep6g via Digitalmars-d-learn

On Sunday, 15 August 2021 at 20:41:51 UTC, james.p.leblanc wrote:
I have been trying to get a working example of slice assignment 
operator
overloading ... and am befuddled.  From the spec (section 
20.6.2), the

code below appears:

struct A
{
int opIndexAssign(int v);  // overloads a[] = v
int opIndexAssign(int v, size_t[2] x);  // overloads 
a[i .. j] = v
int[2] opSlice(size_t x, size_t y); // overloads i 
.. j

}

void test()
{
A a;
int v;

a[] = v;  // same as a.opIndexAssign(v);
a[3..4] = v;  // same as a.opIndexAssign(v, 
a.opSlice(3,4));

}


I have no experience with this, but from a cursory look it seems 
that that example is wrong.


For starters, the type of `opIndexAssign`'s second parameter must 
match the return type of `opSlice`. This is easily fixed, but the 
code still doesn't work.


Further down on the spec page [1], there is this little table:

| op| rewrite 
 |

|---|--|
| `arr[1, 2..3, 4] = c` | `arr.opIndexAssign(c, 1, 
arr.opSlice!1(2, 3), 4)`|
| `arr[2, 3..4] += c`   | `arr.opIndexOpAssign!"+"(c, 2, 
arr.opSlice!1(2, 3))` |


Note the `!1` on `opSlice`. So you need to make `opSlice` a 
template with an integer parameter.


Working example:

```d
import std.stdio;

struct A
{
int opIndexAssign(int v, size_t[2] x)
{
writeln("opIndexAssign: ", v, ", ", x);
return v;
}
size_t[2] opSlice(size_t i)(size_t x, size_t y)
{
return [x, y];
}
}

void main()
{
A a;
int v = 42;
a[3..4] = v; /* Prints "opIndexAssign: 42, [3, 4]". */
}
```


[1] https://dlang.org/spec/operatoroverloading.html#slice


Re: compare types of functions.

2021-08-04 Thread ag0aep6g via Digitalmars-d-learn

On 02.08.21 22:14, vit wrote:

Why this doesn't work:
```d
template DestructorType(T){

 alias Get(T) = T;

     alias DestructorType = Get!(typeof((void*){
     T tmp;
     }));
}

struct Foo{

     ~this()@safe{}
}
```


```d
void main(){
     //Error: static assert:  `is(void function(void*) pure nothrow 
@nogc @safe : void function(void*) @safe)` is false
     static assert(is(void function(void*)pure nothrow @safe @nogc : 
DestructorType!Foo));


}

```

but this work:
```d

void main(){

     alias X = void function(void*)@safe;


     static assert(is(void function(void*)pure nothrow @safe @nogc : 
DestructorType!Foo));


}
```


Looks like you found a compiler bug. An unused alias should have any effect.


Re: Creating immutable arrays in @safe code

2021-07-18 Thread ag0aep6g via Digitalmars-d-learn

On 17.07.21 15:56, ag0aep6g wrote:
At a glance, the only meaningful use of `PURE.strong` seems to be in 
dcast.d, introduced by the PR you linked. Changing that to `PURE.const_` 
doesn't break any tests for me. So I'm inclined to believe that 
`PURE.strong` is nonsense, and that `PURE.const_` already means 
"strongly pure".


However, changing that instance doesn't fix the issue. Apparently, DMD 
doesn't even recognize


     int[] array(const int[] input) pure { ... }

as `PURE.const_`.


I've dug a bit deeper, and apparently I'm to blame for confusing things. 
In issue 15862 [1], I stated that functions with mutable indirections in 
the return type cannot be strongly pure. That's wrong, but it seems to 
have found its way into DMD.


The core of issue 15862 is true: Two calls to `array` cannot be merged 
into one. But that doesn't make it weakly pure. Mutability in the return 
type is distinct from weak/strong purity.


These are all true:

* `array` is "strongly pure".
* `array` is a "pure factory function".
* The result of one call to `array` cannot be reused for another, 
identical call.



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


Re: Creating immutable arrays in @safe code

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

On 17.07.21 14:56, Dennis wrote:

On Saturday, 17 July 2021 at 12:05:44 UTC, ag0aep6g wrote:
Hm, as far as I understand, "strongly pure" doesn't require 
`immutable` parameters. `const` should be enough. The spec says: "A 
strongly pure function has no parameters with mutable indirections" [1].


I just took the description from the source code:
```D
enum PURE : ubyte
{
     impure  = 0,    // not pure at all
     fwdref  = 1,    // it's pure, but not known which level yet
     weak    = 2,    // no mutable globals are read or written
     const_  = 3,    // parameters are values or const
     strong  = 4,    // parameters are values or immutable
}
```


That looks off to me. Unless DMD has some secret knowledge about a 
shortcoming in the established definition of "strongly pure", I think 
those enum values are badly named.


At a glance, the only meaningful use of `PURE.strong` seems to be in 
dcast.d, introduced by the PR you linked. Changing that to `PURE.const_` 
doesn't break any tests for me. So I'm inclined to believe that 
`PURE.strong` is nonsense, and that `PURE.const_` already means 
"strongly pure".


However, changing that instance doesn't fix the issue. Apparently, DMD 
doesn't even recognize


int[] array(const int[] input) pure { ... }

as `PURE.const_`.


I don't know whether the spec or code is correct.


When it comes to purity, another piece in the puzzle is David 
Nadlinger's article:


https://klickverbot.at/blog/2012/05/purity-in-d/

There, a function with a `const int[]` parameter is described as 
"strongly pure".


As far as I can remember, when DMD and that article disagreed in the 
past, DMD was wrong.


[...]
Yup, [remember 
this](https://github.com/dlang/dmd/pull/8035#discussion_r174771516)?


Hehe, I knew I had complained about it before.

It's doubly bad: (1) We're missing out on bug fixes, because they're 
hidden behind `-preview=dip1000` for no reason. (2) When 
`-preview=dip1000` ever becomes the default, code will break that 
doesn't even use the features of DIP 1000.


Re: Creating immutable arrays in @safe code

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

On 17.07.21 13:05, Dennis wrote:
There used to be a complex `isReturnIsolated` check, but the [fix for 
issue 15660](https://github.com/dlang/dmd/pull/8048) reduced it to a 
check 'is the function strongly `pure`' which means 'parameters are 
values or immutable'. To reduce code breakage, the 'strong pure' 
requirement is only needed with -dip1000, which is why your example 
doesn't work with it.


Hm, as far as I understand, "strongly pure" doesn't require `immutable` 
parameters. `const` should be enough. The spec says: "A strongly pure 
function has no parameters with mutable indirections" [1]. Seems to me 
that the fix is buggy.


Also, conflating other issues with DIP1000 is such an obviously terrible 
idea.



[1] https://dlang.org/spec/function.html#pure-functions


Re: Creating immutable arrays in @safe code

2021-07-16 Thread ag0aep6g via Digitalmars-d-learn

On 17.07.21 00:27, H. S. Teoh wrote:

Hmm, OK. Not sure why .array isn't being inferred as unique... but yeah,
you probably have to resort to using @trusted with .assumeUnique.


In addition to `pure`, you also need a const/immutable input and a 
mutable output, so that the output cannot be a slice of the input.


For std.array.array it might be possible to carefully apply `Unqual` to 
the element type.


I tried doing that, but `-preview=dip1000` causes trouble. This fails:


int[] array(const int[] input) pure nothrow @safe
{
int[] output;
foreach (element; input) output ~= element;
return output;
}
void main() pure nothrow @safe
{
const int[] c = [1, 2, 3];
immutable int[] i = array(c);
/* Without `-preview=dip1000`: works, because the result is unique.
With `-preview=dip1000`: "Error: cannot implicitly convert". */
}


I'm not sure what's going on. `pure` being involved makes me think of 
issue 20150. But it also fails with my fix for that issue. So maybe it's 
another bug.


Re: mixin template's alias parameter ... ignored ?

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

On 13.07.21 03:03, someone wrote:

On Monday, 12 July 2021 at 23:28:29 UTC, ag0aep6g wrote:

[...]

I'm not sure where we stand with `in`


You mean *we* = D developers ?


Yes. Let me rephrase and elaborate: I'm not sure what the current status 
of `in` is. It used to mean `const scope`. But DIP1000 changes the 
effects of `scope` and there was some discussion about its relation to `in`.


Checking the spec, it says that `in` simply means `const` unless you use 
`-preview=in`. The preview switch makes it `const scope` again, but 
that's not all. There's also something about passing by reference.


https://dlang.org/spec/function.html#in-params

[...]
For a UDT like mine I think it has a lot of sense because when I think 
of a string and I want to chop/count/whatever on it my mind works 
one-based not zero-based. Say "abc" needs b my mind works a lot easier 
mid("abc", 2, 1) than mid("abc", 1, 1) and besides I am *not* returning 
a range or a reference slice to a range or whatever I am returning a 
whole new string construction. If I would be returning a range I will 
follow common sense since I don't know what will be done thereafter of 
course.


I think you're setting yourself up for off-by-one bugs by going against 
the grain like that. Your functions are one-based. The rest of the D 
world, including the standard library, is zero-based. You're bound to 
forget to account for the difference.


But it's your code, and you can do whatever you want, of course. Just 
looked like it might be a mistake.


Re: mixin template's alias parameter ... ignored ?

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

On Monday, 12 July 2021 at 22:35:27 UTC, someone wrote:

On Monday, 12 July 2021 at 05:33:22 UTC, ag0aep6g wrote:

[...]
Teach me please: if I declare a variable right after the 
function declaration like this one ... ain't scope its default 
visibility ? I understand (not quite sure whether correct or 
not right now) that everything you declare without explicitly 
stating its visibility (public/private/whatever) becomes scope 
ie: what in many languages are called a local variable. What 
actually is the visibility of lstrSequence without my scope 
declaration ?


`scope` is not a visibility level.

`lstrSequence` is local to the function, so visibility (`public`, 
`private`, ...) doesn't even apply.


Most likely, you don't have any use for `scope` at the moment. 
You're obviously not compiling with `-preview=dip1000`. And 
neither should you, because the feature is not ready for a 
general audience yet.


[...]
Style: `scope` does nothing on `size_t` parameters 
(throughout).


A week ago I was using [in] almost everywhere for parameters, 
ain't [in] an alias for [scope const] ? Did I get it wrong ? 
I'm not talking style here, I'm talking unexpected (to me) 
functionality.


I'm not sure where we stand with `in`, but let's say that it 
means `scope const`. The `scope` part of `scope const` still does 
nothing to a `size_t`. These are all the same: `in size_t`, 
`const size_t`, `scope const size_t`.



scope size_t lintRange1 = lintStart - cast(size_t) 1;
scope size_t lintRange2 = lintRange1 + lintCount;



Possible bug: Why subtract 1?


Because ranges are zero-based for their first argument and 
one-based for their second; ie: something[n..m] where m should 
always be  one-beyond than the one we want.


That doesn't make sense. A length of zero is perfectly fine. It's 
just an empty range. You're making `lintStart` one-based for no 
reason.




Re: mixin template's alias parameter ... ignored ?

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

On 12.07.21 03:37, someone wrote:
I ended up with the following (as usual advice/suggestions welcomed): 
[...]> alias stringUTF16 = dstring; /// same as immutable(dchar)[];> 
alias stringUTF32 = wstring; /// same as immutable(wchar)[];
Bug: You mixed up `wstring` and `dstring`. `wstring` is UTF-16. 
`dstring` is UTF-32.


[...]
public struct gudtUGC(typeStringUTF) { /// UniCode grapheme 
cluster‐aware string manipulation


Style: `typeStringUTF` is a type, so it should start with a capital 
letter (`TypeStringUTF`).


[...]

    private size_t pintSequenceCount = cast(size_t) 0;
    private size_t pintSequenceCurrent = cast(size_t) 0;


Style: There's no need for the casts (throughout).

[...]
    @safe public typeStringUTF encode() { /// UniCode grapheme cluster 
to UniCode UTF‐encoded string


   scope typeStringUTF lstrSequence = null;

[...]

   return lstrSequence;

    }


Bug: `scope` makes no sense if you want to return `lstrSequence` 
(throughout).


    @safe public typeStringUTF toUTFtake( /// UniCode grapheme cluster 
to UniCode UTF‐encoded string

   scope const size_t lintStart,
   scope const size_t lintCount = cast(size_t) 1
   ) {

Style: `scope` does nothing on `size_t` parameters (throughout).

[...]

   if (lintStart <= lintStart + lintCount) {

[...]

  scope size_t lintRange1 = lintStart - cast(size_t) 1;


Possible bug: Why subtract 1?


  scope size_t lintRange2 = lintRange1 + lintCount;

  if (lintRange1 >= cast(size_t) 0 && lintRange2 <= 
pintSequenceCount) {


Style: The first half of that condition is pointless. `lintRange1` is 
unsigned, so it will always be greater than or equal to 0. If you want 
to defend against overflow, you have to do it before subtracting.


[...]

  }

   }

[...]

    }

[...]
    @safe public typeStringUTF toUTFpadL( /// UniCode grapheme cluster 
to UniCode UTF‐encoded string

   scope const size_t lintCount,
   scope const typeStringUTF lstrPadding = cast(typeStringUTF) r" "


Style: Cast is not needed (throughout).


   ) {

[...]

    }

[...]

}

[...]


Re: what is D's idiom of Python's list.extend(another_list)?

2021-06-21 Thread ag0aep6g via Digitalmars-d-learn

On 21.06.21 09:02, Mike Parker wrote:

On Monday, 21 June 2021 at 06:16:15 UTC, mw wrote:


Ha! great. I didn't know `~` works for both single elements and array!


`~` by itself is the concatenation operator and only works with two 
array operands. `~=` is the append operator and can append arrays or 
single elements.


`~` works just fine with single elements:

void main()
{
import std.stdio;
int[] a = [2, 3, 4];
writeln(1 ~ a ~ 5); /* [1, 2, 3, 4, 5] */
}


Re: @trusted methods

2021-06-18 Thread ag0aep6g via Digitalmars-d-learn

On 18.06.21 14:40, vit wrote:
Are asserts enough to make method @trusted or is something like throw 
exception or return error code necessary?
Asserts are a debugging feature. They're not suitable to ensure safety, 
because they're simply skipped in release mode.


`assert(false);` is the exception. It aborts the program even in release 
mode. So you can use it to bail out when your expectations fail.


So:

assert(expected); /* Don't do this. */

import std.exception: enforce;
enforce(expected); /* Instead, do this */
if (!expected) throw new Exception("..."); /* or this */
if (!expected) assert(false); /* or this. */


Re: In general, who should do more work: popFront or front?

2021-06-14 Thread ag0aep6g via Digitalmars-d-learn

On 15.06.21 07:17, mw wrote:

https://dlang.org/library/std/range/primitives/front.html
the 2nd decl:
dchar front(T) (
   scope const(T)[] a
) pure @property @safe
if (isAutodecodableString!(T[]));

you can see `const`


but

https://dlang.org/library/std/range/primitives/pop_front.html
void popFront(C) (
   scope ref inout(C)[] str
) pure nothrow @trusted
if (isAutodecodableString!(C[]));

it's `ref inout`, which means the passed-in object is intended to be 
modified inside the method in-place.


`const` and `inout` mean the same thing here: Both functions cannot 
modify the elements of the array.


The difference lies in `ref` alone. `front` receives a copy, so it can't 
change the length of the array you pass in. `popFront` receives by 
reference, so it can (and does).


Re: cannot take address of scope local in safe function

2021-06-14 Thread ag0aep6g via Digitalmars-d-learn

On 13.06.21 19:49, vit wrote:
Is possible create and use scope output range allocated on stack in 
@safe code?


Example:
```d
//-dip1000

     struct OutputRange{
     private bool valid = true;
     private void* ptr;
     int count = 0;

     void put(Val)(auto ref scope Val val){
     assert(this.valid == true);
     this.count += 1;
     }


     ~this()scope pure nothrow @safe @nogc{
     this.valid = false;
     }


     }

     void main()@safe pure nothrow @nogc{
     import std.algorithm : copy;
     import std.range : only;

     scope OutputRange or;

     only(1, 2, 3, 4).copy();   ///Error: cannot take address of 
`scope` local `or` in `@safe` function `main`

     assert(or.count == 4);
     }

```


You're trying to create a `scope` pointer that points to another `scope` 
pointer. That's not supported. You can only have one level of `scope`.


The first level of `scope` is explicit in `scope OutputRange or;`. The 
second level is implicit in ``, because the address of a local 
variable is necessarily a `scope` pointer.


As it's written, the first level isn't actually needed in your code. So 
maybe you can just remove `scope` from `or` be done. But let's assume 
that it really is needed for some reason.


The second level you do need. Without it, the assert fails. But you 
wouldn't need the pointer if `copy` took the argument by `ref`, because 
`ref` has a sort of implied `scope` that can be combined with an actual 
`scope` to give two levels of protection. So you could write your own 
`copy` with a `ref` parameter.


Or you can just write out what `copy` does in `main`, sidestepping the 
issue:



foreach (e; only(1, 2, 3, 4))
{
or.put(e);
}


None of this is ideal, of course.


Re: cannot take address of scope local in safe function

2021-06-13 Thread ag0aep6g via Digitalmars-d-learn

On Sunday, 13 June 2021 at 16:27:18 UTC, vit wrote:

Why I can take address of Foo variable but not Bar?

```d
//-dip1000

struct Foo{
private double d;
}

struct Bar{
private void* ptr;
}



void main()@safe{
///this is OK:
{
scope Foo x;
scope ptr = 
}

///Error: cannot take address of `scope` local `x` in 
`@safe` function `main`:

{
scope Bar x;
scope ptr = 
}
}
```


`scope` affects indirections (i.e. pointers). `Foo` doesn't 
contain any indirections, so `scope` doesn't mean anything for 
it. The compiler just ignores it. It's like you wrote `Foo x;` 
without `scope`.


`Bar` does contain an indirection, so `scope` actually matters 
and you get the error.


Re: Cast class reference to pointer of another class?

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

On Saturday, 29 May 2021 at 21:01:14 UTC, JN wrote:
this code compiles. Why? What is even the result in "f" in this 
case?


On Saturday, 29 May 2021 at 21:03:12 UTC, JN wrote:

fixed formatting:

```d
struct Foo
{
}

class Bar
{
}

void main()
{
Bar b = new Bar();
Foo* f = cast(Foo*)b;
}
```


You're writing @system code, so dangerous casts are allowed. It's 
no surprise that the code compiles. If you want to be safeguarded 
against such things, use @safe.


The result is a class object being reinterpreted as a struct 
object. Usually, that's just nonsense. But it might be useful for 
some expert who wants to tinker with the object's internals.


Re: stack out of scope ?

2021-05-16 Thread ag0aep6g via Digitalmars-d-learn

On 16.05.21 19:24, Alain De Vos wrote:

On Sunday, 16 May 2021 at 16:58:15 UTC, H. S. Teoh wrote:

[...]
Though I believe if you compile with -dip25 -dip1000 the compiler 
should emit an error for the above code.  If not, please file a bug 
against -dip1000.



T


I use ldc2. No dip flags here.


ldc2 understands `-dip1000`. It also understands the newer 
`-preview=dip1000`.


More importantly, the code needs to be @safe. @system code is not 
checked for this kind of error.


Re: ref struct member function

2021-05-14 Thread ag0aep6g via Digitalmars-d-learn

On 14.05.21 12:00, PinDPlugga wrote:
Hi thank you both for your answers. I had understood from an earlier 
chapter how this could introduce a bug, but I was confused because the 
warning suggests attaching ```return``` to the parameter, which is empty 
in the declaration.


`this` is considered a hidden parameter. Every non-static method has it.

So my next question would be how come ref based operator overloads are 
not labelled as return and do not show this warning?


``` D
struct Fraction {
     auto n = 0L;
     auto d = 1L;

     ref Fraction opUnary(string op)()
     if (op == "++") {
     n += d;
     return this;
     }
}

ref Fraction foo() {
     auto f = Fraction(1, 3);

     // Same bug as with reduce
     return ++f;
}
```


Note that opUnary is not an ordinary method. It's a template. That means 
attributes are inferred [1], including the `return` attribute. I.e., the 
compiler adds `return` to the signature for you, just like Steven 
suggested you do manually.


Try omitting the return type of `reduce` in your original code:

 ref reduce() { ... }

That also enables attribute inference, and your code will compile.


[1] https://dlang.org/spec/function.html#function-attribute-inference


Re: What's a good approach to DRY with the block code of a case-statement?

2021-04-26 Thread ag0aep6g via Digitalmars-d-learn

On Monday, 26 April 2021 at 20:39:55 UTC, Jack wrote:
I have a block of code that the only thing that change is the 
type passed in one of the template functions called so I'd like 
to make a DRY for this. But I'm not just replacing by a 
function due to control-flow, for example, there are 
if-statements where one just break and the other return 0. I 
think I could do something with mixin() that would kinda mimic 
C's macro but I still find it messy. Any alternatives?


```d
static int doSomething()
{
switch(val)
{
case VAL_FOO:
auto obj = getObject!MyType(someData); // this is the 
type

   // that changes
if(obj.shouldExit()) break;

auto m = Message(...);
if(obj.doSomethingElse(m)) return 0;
break;

   // ...

   default:
}

return doSomethingY();
}
```


I think you're looking for this D idiom:

```d
sw: switch (rt_value)
{
static foreach (ct_value; ct_values)
{
case ct_value: some_template!ct_value; break sw;
}
}
```

Applied to your code it might look like this:

```d
import std.meta: AliasSeq;
alias stuff = AliasSeq!(VAL_FOO, MyType, VAL_BAR, MyOtherType, /* 
... */);

sw: switch (val)
{
static foreach (i; 0 .. stuff.length / 2)
{
case stuff[i]:
auto obj = getObject!(stuff[i + 1])(someData);
if(obj.shouldExit()) break sw;
auto m = Message(...);
if(obj.doSomethingElse(m)) return 0;
break sw;
}
}
```


Re: Extern/scope issue

2021-04-03 Thread ag0aep6g via Digitalmars-d-learn

On 03.04.21 15:34, DLearner wrote:

The following produces the expected result.
However, changing extern(C) to extern(D) causes linker failures.
To me, that is bizarre.
Testmain:
extern(C) int xvar;

[...]


Testmod:
extern extern(C) int xvar;


With `extern (C)`, those two `xvar`s refer to the same data.
Without `extern (C)` (or with `extern (D)`), they are distinct variables 
with no relation to another. In D, you don't re-declare another module's 
symbols. You import the other module.



module testmain;

import std.stdio: writeln;
import testmod: testsub, xvar;

void main()
{
xvar = 1;
writeln(xvar); /* prints "1" */
testsub();
writeln(xvar); /* prints "2" */
}



module testmod;

int xvar; /* same as `extern (D) int xvar;` */

void testsub()
{
   xvar = 2;
}



Re: Need for speed

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

On 01.04.21 21:53, Steven Schveighoffer wrote:
Maybe, but I wasn't responding to that, just your statement not to 
recommend -boundscheck=off. In any case, it wouldn't hurt, right?


Right.


Re: Need for speed

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

On 01.04.21 21:36, Steven Schveighoffer wrote:

On 4/1/21 3:27 PM, ag0aep6g wrote:

On 01.04.21 21:00, Berni44 wrote:

```
ldc2 -O3 -release -boundscheck=off -flto=full 
-defaultlib=phobos2-ldc-lto,druntime-ldc-lto speed.d

```

[...]
Yes, but you can recommend `-boundscheck=safeonly`, which leaves it on 
for @safe code.

`-O -release` already does that, doesn't it?


Re: Need for speed

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

On 01.04.21 21:00, Berni44 wrote:

```
ldc2 -O3 -release -boundscheck=off -flto=full 
-defaultlib=phobos2-ldc-lto,druntime-ldc-lto speed.d

```


Please don't recommend `-boundscheck=off` to newbies. It's not just an 
optimization. It breaks @safe. If you want to do welding without eye 
protection, that's on you. But please don't recommend it to the new guy.


Re: Need for speed

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

On Thursday, 1 April 2021 at 16:52:17 UTC, Nestor wrote:
I was hoping to beat my dear Python and get similar results to 
Go, but that is not the case neither using rdmd nor running the 
executable generated by dmd. I am getting values between 
350-380 ms, and 81ms in Python.

[...]

```
for (int number = 0; number < 10; ++number)
{
auto rnd = Random(unpredictableSeed);
auto n = uniform(0, 100, rnd);
mylist ~= n;
}
```

```
for _ in range(10):
mylist.append(random.randint(0,100))
```


In the D version, you're re-seeding the random number generator 
on every loop. That takes time. You're not doing that in the 
Python version.


Move `auto rnd = ...;` out of the loop, and you will get better 
times. Or just use the default generator with `uniform(0, 100)`.


Re: Implicit conversion of unique chars[] to string

2021-03-23 Thread ag0aep6g via Digitalmars-d-learn

On 23.03.21 02:07, Steven Schveighoffer wrote:

const(char)[] x = "foo";
string chained = chainPath(x, "bar").array;

Error: cannot implicitly convert expression array(chainPath(x, "bar")) 
of type const(char)[] to string


And the answer is complex. You can't accept a const range, because they 
don't work. The only way to have purity infer uniqueness is to accept 
paramters that the result could not have come from. Usually this means 
accepting const and returning mutable.


Ah, right. Purity was a red herring then. If you put a `const(char)[]` 
in and you get a `const(char)[]` out, then the compiler must assume that 
it might be the same one.


We could possibly change `.array` to return a `char[]`. Uniqueness would 
still fail when you pass a `char[]` in, but that could be worked around 
by adding a const temporary.


Re: Implicit conversion of unique chars[] to string

2021-03-22 Thread ag0aep6g via Digitalmars-d-learn

On 22.03.21 21:38, Per Nordlöw wrote:

Am I the only one being annoyed by the fact that

     chainPath(...).array

doesn't implicit convert to string despite the array returned from 
.array is allocated by the GC.


Works for me:


import std.array: array;
import std.path: chainPath;
void main()
{
string chained = chainPath("foo", "bar").array;
}


Uniqueness is being inferred based on purity. If it doesn't work for 
you, then you're probably doing something impure.


Re: question about ref keyword

2021-03-18 Thread ag0aep6g via Digitalmars-d-learn

On Thursday, 18 March 2021 at 16:59:24 UTC, Jack wrote:

let's assume this class:

class C
{
private S m_s;

this()
{
m_s = S(30);
}

ref S value() { return m_s; }
ref S value(ref S s)
{
return m_s = s;
}
}

and I do something like this:

auto s1 = S(40);
auto c = new C();
c.value = s1;
s1.n = 80;


give that value has ref in its signature, the s1 is passed as a 
"pointer" right?


right

also, when I do: m_s = s; m_s is a copy of s1 or a reference to 
it?


a copy

setting s1.n to 80 in the next line doesn't seem to change 
c.value so it seems it passed s1 as a pointer but when it comes 
to assignment a copy was made?


You got it.

If you want the pointer, you can get it taking the address of s: 
`S* p = `.


Re: Compiler module import graph

2021-03-13 Thread ag0aep6g via Digitalmars-d-learn

On 13.03.21 15:20, frame wrote:

Is there a tool to view module import graph?

The compiler verbose output shows that the module is imported/parsed but 
not why. I wan't to avoid unnecessary imports to speed up compile times 
or avoid issues if the module contents are not fully compatible with the 
current compile target being in development.


`dmd -deps` shows what imports what.

https://dlang.org/dmd-linux.html#switch-deps

Be aware that there is a bug where DMD misses some edges in the graph:
https://issues.dlang.org/show_bug.cgi?id=21238


Re: unittest compiles w/o error though module file is not named after the module

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

On 06.02.21 16:05, kdevel wrote:

On Saturday, 6 February 2021 at 14:52:57 UTC, Adam D. Ruppe wrote:

[...]

That one `import p;` is kinda weird, it should probably complain then 
you imported one thing and got another, but generally the name not 
matching is no problem at all.


```main.d (version 2)
// import x;
unittest {
//   import pp: foo; // wrong name is accepted if x is imported
    import p: foo;
    foo;
}
```


Looks like .


Re: Type of string literal concatenated with non-immutable char array

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

On 31.01.21 22:48, Per Nordlöw wrote:

Why isn't

     "Name " ~ name ~ " could not be found"

implicitly convertible to `string`?


If concatenation is guaranteed to allocate a new array, then it should 
be "strongly pure", and the conversion should work. I'm not sure if it 
is guaranteed to allocate a new array.



Would

class NameLookupException : Exception
{
     this(scope const(char)[] name) @trusted {
     super("Name " ~ cast(string)name ~ " could not be found");
     }
}

be ok?


Only if you know for sure that you're dealing with a compiler bug here.

As another workaround, you can use std.conv.text:

import std.conv: text;
super(text("Name ", name, " could not be found"));


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


  1   2   3   4   5   6   7   >