Re: T[] opIndex() Error: .. signal 11

2023-10-04 Thread ag0aep6g via Digitalmars-d-learn

On 03.10.23 20:26, Paul Backus wrote:
Naturally, this lowering is completely absent from [the language spec's 
section on `foreach`.][1] According to the spec, the only ways to 
iterate over a `struct` type are `opApply` and the input range interface.


I think it would probably be less confusing to have both `opApply` and 
`empty`/`front`/`popFront` take precedence over this lowering, but I 
have no idea how much existing code would be broken by such a change. At 
the very least, though, this needs to be documented.


[1]: https://dlang.org/spec/statement.html#foreach-statement


For some further reading, there's an open issue about the unexpected 
slicing: https://issues.dlang.org/show_bug.cgi?id=14619


Re: Question about interface implementation

2023-05-21 Thread ag0aep6g via Digitalmars-d-learn

On 21.05.23 12:55, Theo wrote:
As for the other part, if I use an abstract base class, I *must* 
indicate when i'm overriding the base class method by explicately saying 
'override'.


I wouldn't mind if implementing interface methods required `override` as 
well. I don't know if there is a rationale for the inconsistency.




Re: Question about interface implementation

2023-05-21 Thread ag0aep6g via Digitalmars-d-learn

On 21.05.23 12:28, ag0aep6g wrote:
Since @trusted functions are guaranteed (by the programmer) 
to be safe, they are allowed to overload/implement @safe 
functions/prototypes.


*override


Re: Question about interface implementation

2023-05-21 Thread ag0aep6g via Digitalmars-d-learn

On 21.05.23 11:55, Theo wrote:

class MerchantShip : Ship
{
     private int speed = 0; // If only I had 'private(this)' !!

     // how do I know this method is actually an implementation of an 
interface method

     // and not a method specific to this class?
     // AND ... how come I can change a @safe interface method into a 
@trusted one?

     public @trusted void setSpeed(int speed)
     {
     int *s = void; // Mmmm.. and my interface all had @safe methods!!
     this.speed = speed;
     }

[...]

}


As far as I understand, a method that has the right signature is always 
an implementation of the interface. There is no way to make a method of 
the same name, with the same parameters, etc. that is "specific to the 
class".


@trusted means that you're allowed to use @system features in the 
implementation while the function must follow the restrictions of @safe 
when called. Since @trusted functions are guaranteed (by the programmer) 
to be safe, they are allowed to overload/implement @safe 
functions/prototypes.


If you create an @trusted function that is not safe to call, that's an 
error on your part.


Re: Given an object, how to call an alias to a member function on it?

2023-05-03 Thread ag0aep6g via Digitalmars-d-learn

On 03.05.23 13:13, Nick Treleaven wrote:

On Tuesday, 2 May 2023 at 13:06:41 UTC, ag0aep6g wrote:

void fun(alias method)(C c)
{
    void delegate() dg;
    dg.funcptr = 
    dg.ptr = cast(void*) c;
    dg();
}


This also works:

void fun(alias method)(C c)
{
     void delegate() dg = 
     dg();
}



No, it doesn't. You're not using the alias. You're just accessing 
`c.method` directly. If the actual method weren't called "method", you'd 
get an error.


Re: Given an object, how to call an alias to a member function on it?

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

On 02.05.23 14:52, Quirin Schroll wrote:
How do I invoke the member function in a reliable way? Given `obj` of 
the type of the object, I used `mixin("obj.", __traits(identifier, 
memberFunc), "(params)")`, but that has issues, among probably others, 
definitely with visibility. (The member function alias is a template 
parameter.)


Construct a delegate from the alias and the object, and call that delegate:


class C
{
int field = 42;
void method() { import std.stdio; writeln(field); }
}

void fun(alias method)(C c)
{
void delegate() dg;
dg.funcptr = 
dg.ptr = cast(void*) c;
dg();
}

void main()
{
fun!(C.method)(new C); /* prints "42" */
}



Re: Linking external functions?

2023-04-18 Thread ag0aep6g via Digitalmars-d-learn

On Tuesday, 18 April 2023 at 20:05:05 UTC, DLearner wrote:

Is the declaration inside main not visible to the linker?


It affects the (fully qualified and mangled) name of the 
function. Compare:


```d
extern(C) void ExtCallee();
pragma(msg, ExtCallee.mangleof); /* ExtCallee (correct name) */
void main()
{
extern(C) void ExtCallee();
pragma(msg, ExtCallee.mangleof); /* 
_D7ExtMain4mainFZ9ExtCalleeUZv (incorrect) */

}
```

I don't know the rationale behind that behavior, if there is one. 
Generally, just put your `extern(C)` prototypes in module scope.


Re: Linking external functions?

2023-04-18 Thread ag0aep6g via Digitalmars-d-learn

On Tuesday, 18 April 2023 at 19:49:04 UTC, DLearner wrote:

```
void main() {
   import std.stdio;
   extern(C) void ExtCallee();
```


Move that declaration out of main.


Re: The Phobos Put

2023-03-29 Thread ag0aep6g via Digitalmars-d-learn

On Wednesday, 29 March 2023 at 19:49:47 UTC, Ali Çehreli wrote:
I thought Salih was proposing two more overloads to the 
existing put(). When I copy the existing put(), which takes 
'ref R', not R[], then the code does not compile:


auto put(R)(R[] range, R[] source)
  => putImpl(range, source);

auto put(R)(ref R[] range, R[] source)
  => putImpl(range, source);


[...]


void put(R, E)(ref R r, E e)
{
  // This is from Phobos <---
}


I understand Salih's ref `put` to be same as yours: a stand-in 
for the one that is already in Phobos. So he's proposing to add 
the non-ref one.


But regardless of Salih's exact intent, the broader point is: a 
non-ref overload could be added to Phobos. And that would enable 
`a[1..$-1].phobos_put([2, 3])`. Which is what he asked about 
originally.


Re: The Phobos Put

2023-03-29 Thread ag0aep6g via Digitalmars-d-learn

On Wednesday, 29 March 2023 at 16:44:31 UTC, Ali Çehreli wrote:

On 3/29/23 09:27, Salih Dincer wrote:

> In this way,
> it could also be used directly with slices. For example:

> auto put(R)(R[] range, R[] source)
>=> putImpl(range, source);

That's for rvalues.

> auto put(R)(ref R[] range, R[] source)
>=> putImpl(range, source);

That's for lvalues.

If you are proposing keeping the current ref-taking Phobos 
put() as well, then the following call would be ambiguous:


  slice.put([2]);  // Compilation ERROR


As far as I understand, you're saying that we cannot overload on 
`ref`. But we can. Salih's code demonstrates just that.


void f(ref int x) {}
void f(int x) {}
void main() { int x; f(x); f(42); } /* no errors */


Re: read/peek and automatically advance index in buffer

2023-03-16 Thread ag0aep6g via Digitalmars-d-learn

On Thursday, 16 March 2023 at 18:39:00 UTC, jwatson-CO-edu wrote:

```d
int rtnVal = buffer.peek(int,Endian.bigEndian)();
// Error: found `,` when expecting `.` following int
```


You just forgot the exclamation mark there.


Re: How can I get the scalar type of a pointer to pointer (and in even deeper levels)

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

On 11.03.23 14:22, rempas wrote:

On Saturday, 11 March 2023 at 12:59:59 UTC, ag0aep6g wrote:


alias Foo(T : U*, U) = Foo!U;
alias Foo(T) = T;
static assert(is(Foo!(int*) == int));
static assert(is(Foo!(int**) == int));
static assert(is(Foo!(int***) == int));
static assert(is(Foo!(int) == int));


Wait, but "Foo" is defined twice and it doesn't let me compile...


You're doing something wrong then.

Don't put the Foo declarations in a function or unittest.


Re: How can I get the scalar type of a pointer to pointer (and in even deeper levels)

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

On 11.03.23 13:49, rempas wrote:
but what 
about pointers to pointers like: `int`? Is there a way that I would 
be able to always get the scalar type of a pointer regardless of how 
many levels it is? As always, I'm searching for a solution that will 
work in `BetterC`.


alias Foo(T : U*, U) = Foo!U;
alias Foo(T) = T;
static assert(is(Foo!(int*) == int));
static assert(is(Foo!(int**) == int));
static assert(is(Foo!(int***) == int));
static assert(is(Foo!(int) == int));


Re: Transform static immutable string array to tuple.

2023-02-19 Thread ag0aep6g via Digitalmars-d-learn

On Sunday, 19 February 2023 at 11:08:34 UTC, realhet wrote:
Is there a better way to transform a string array to a tuple or 
to an AliasSeq?


```
mixin(customSyntaxPrefixes.format!`tuple(%(%s,%))`)
```


https://dlang.org/phobos/std_meta.html#aliasSeqOf


Re: Why does this code only work with `std.conv.to` whilst not with `cast`?

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

On 08.01.23 12:29, thebluepandabear wrote:

```D
interface ICustomDrawable {
     void render(sfRenderWindow* renderWindow);
}

[...]> class Button : ICustomDrawable {
[...]

}

[...]

class StackLayout : ICustomDrawable {

[...]

     ICustomDrawable[] _children;
}
```

For some reason, when I want to cast the `children` (property), only the 
second example works:


1.

```D
foreach (Button button; cast(Button[])(_boardSizeRow.children)) {
     button.update(event, _renderWindow);
}
```

2.

```D
foreach (Button button; to!(Button[])(_boardSizeRow.children)) {
     button.update(event, _renderWindow);
}
```


Two things you need to know:

1. While an interface reference implicitly converts to a compatible 
class reference, the resulting pointer is slightly different.



interface I {}
class C : I {}
void main()
{
C c = new C;
I i = c;
import std.stdio;
writeln(cast(void*) c); /* e.g. 7F3C140A7000 */
writeln(cast(void*) i); /* e.g. 7F3C140A7010 */
}


2. Casting from one array type to another is done "as a type paint"[1]. 
The elements of the array are reinterpreted, not converted.


But reinterpreting interface references as class references won't work, 
because the pointers will be wrong. You need to convert each element of 
the array (which is what `to` does).



[1] https://dlang.org/spec/expression.html#cast_array


Re: Preventing nested struct destructor accessing stack frame

2022-12-19 Thread ag0aep6g via Digitalmars-d-learn

On 16.12.22 14:07, Nick Treleaven wrote:

This seems to work:

     ~this() @trusted { if ( > cast(void*)1024) i++; }

It would be better if there was a struct property to get the context 
pointer though.


A quick test suggests that the context pointer is the last item in 
`tupleof`. So this might do the trick:


~this() { if (this.tupleof[$ - 1] !is null) i++; }

I don't know if it's guaranteed to work though. Might be an 
implementation detail.


Re: How is this code invalid?

2022-12-16 Thread ag0aep6g via Digitalmars-d-learn
On Saturday, 17 December 2022 at 00:23:32 UTC, thebluepandabear 
wrote:

```D
int[] numbersForLaterUse;

void foo(int[] numbers...) {
   numbersForLaterUse = numbers;
}

struct S {
  string[] namesForLaterUse;

  void foo(string[] names...) {
 namesForLaterUse = names;
  }
}
```

[...]
The thing is, when I run the code I get absolutely no error, so 
how is this exactly a 'bug' if the code runs properly? That's 
what I am confused about. What is the D compiler doing behind 
the scenes?


You're witnessing the wonders of undefined behavior. Invalid code 
can still produce the results you're hoping for, or it can 
produce garbage results, or it can crash, or it can do something 
else entirely. And just because running it once does one thing, 
does not mean that the next run will do the same.


For your particular code, here is an example where 
`numberForLaterUse` end up not being what we pass in:


```d
int[] numbersForLaterUse;

void foo(int[] numbers...) {
   numbersForLaterUse = numbers; /* No! Don't! Bad programmer! 
Bad! */

}

void bar()
{
int[3] n = [1, 2, 3];
foo(n);
}

void main()
{
bar();
import std.stdio;
writeln(numbersForLaterUse); /* prints garbage */
}
```

But again nothing at all is actually guaranteed about what that 
program does. It exhibits undefined behavior. So it could just as 
well print "[1, 2, 3]", making you think that everything is fine.


Re: printf, writeln, writefln

2022-12-06 Thread ag0aep6g via Digitalmars-d-learn

On 07.12.22 01:35, ryuukk_ wrote:

On Tuesday, 6 December 2022 at 23:41:09 UTC, H. S. Teoh wrote:

[...]
In D, strings are not the same as char*.  You should use 
std.conv.fromStringZ to convert the C char* to a D string.

[...]

no, you don't "need" to use std conv


Here is an alternative that doesn't allocate

[...]
     // now we got a len, we can build a D string, remember, it's just a 
slice


     string str = cast(string) ret[0 .. len];


Slicing is exactly what std.string.fromStringz does.

:
"The returned array is a slice of the original buffer. The original data 
is not changed and not copied."


Re: How ptr arithmitic works??? It doesn't make any sense....

2022-12-05 Thread ag0aep6g via Digitalmars-d-learn

On Monday, 5 December 2022 at 15:08:41 UTC, rempas wrote:
Got it! I guess they could also just allow us to use bracket 
notation to do the same thing. So something like:


```d
foreach (i; 0 .. list.length) {
  (cast(int*)ptr[i]) = i;
}
```

This is what happens with arrays anyways. And arrays ARE 
pointers to a contiguous memory block anyways so they could do 
the same with regular pointers. The example also looks more 
readable.


You can use bracket notation with pointers. You just need to move 
your closing parenthesis a bit.


Assuming that `ptr` is a `void*`, these are all equivalent:

```d
(cast(int*) ptr)[i] = whatever;
*((cast(int*) ptr) + i) = whatever;
*(cast(int*) (ptr + i * int.sizeof)) = whatever;
```


Re: How ptr arithmitic works??? It doesn't make any sense....

2022-12-04 Thread ag0aep6g via Digitalmars-d-learn

On Sunday, 4 December 2022 at 16:33:35 UTC, rempas wrote:
First a little bit of theory. A pointer just points to a memory 
address which is a number. So when I add "10" to this pointer, 
it will point ten bytes after the place it was pointing to, 
right?


Not quite. Adding 10 to a T* means adding 10 * T.sizeof.



Re: Why can't D store all UTF-8 code units in char type? (not really understanding explanation)

2022-12-03 Thread ag0aep6g via Digitalmars-d-learn

On 02.12.22 22:39, thebluepandabear wrote:
Hm, that specifically might not be. The thing is, I thought a UTF-8 code 
unit can store 1-4 bytes for each character, so how is it right to say 
that `char` is a utf-8 code unit, it seems like it's just an ASCII code 
unit.


You're simply not using the term "code unit" correctly. A UTF-8 code 
unit is just one of those 1-4 bytes. Together they form a "sequence" 
which encodes a "code point".


And all (true) ASCII code units are indeed also valid UTF-8 code units. 
Because UTF-8 is a superset of ASCII. If you save a file as ASCII and 
open it as UTF-8, that works. But it doesn't work the other way around.


Re: Can't assign extern(C) function pointer to D variable?

2022-11-22 Thread ag0aep6g via Digitalmars-d-learn

On 22.11.22 22:11, XavierAP wrote:
I was surprised when it didn't compile, though I immediately found it 
understandable...

Already read through https://dlang.org/spec/interfaceToC.html
and https://wiki.dlang.org/Bind_D_to_C

Is it really the case (that an extern(C) function pointer cannot be 
assigned to a D variable)? Or is it a matter of annotating with the 
right attributes? If so, how?


Works for me:

import core.stdc.stdio: puts;
auto p1 = 
extern (C) int function(const char* s) p2 = 

If you're trying to assign an `extern (C)` function pointer to an 
`extern (D)` one (the default), that cannot work. The compiler would 
emit code using D's calling convention, but the called function would 
assume C's calling convention.


Re: pointer escaping return scope bug?

2022-11-19 Thread ag0aep6g via Digitalmars-d-learn
On Saturday, 19 November 2022 at 15:02:54 UTC, Nick Treleaven 
wrote:

OK, so how do I make `lf` implicitly scope?


By explicit/implicit I just meant this:


scope explicit = new int;
int x;
auto implicit = 


That's probably not helping with whatever you want to accomplish.


Re: pointer escaping return scope bug?

2022-11-19 Thread ag0aep6g via Digitalmars-d-learn

On 19.11.22 15:07, Nick Treleaven wrote:

Hi,
The following seems like a bug to me (reduced code, FILE* changed to int*):
```d
@safe:

struct LockedFile
{
     private int* fps;

     auto fp() return scope => fps;
}

void main()
{
     int* p;
     {
     auto lf = LockedFile(new int);
     p = lf.fp;
     }
     assert(p != null); // address escaped
}
```
There's no error with -dip1000.
I'll file this unless I overlooked something.


Let me rewrite `fp` as a static method. It's easier (for me) to 
understand what's going on that way:



static int* fp(return scope ref LockedFile that)
{
return that.fps;
}


That's essentially just a function that returns its pointer parameter. 
So the program boils down to this:



@safe:
int* fp(return scope int* p) { return p; }
void main()
{
int* p;
{
auto lf = new int;
p = fp(lf);
}
assert(p != null); // address escaped
}


Which is fine, as far as I can tell. `lf` is not `scope`. And when you 
pass it through `fp`, the result is still not `scope`. So escaping it is 
allowed.


You do get an error when you make `lf` `scope` (explicitly or 
implicitly). So everything seems to be in order.


Re: Removing an element from an array

2022-11-11 Thread ag0aep6g via Digitalmars-d-learn
On Friday, 11 November 2022 at 06:10:33 UTC, Alexander Zhirov 
wrote:
On Friday, 11 November 2022 at 05:36:37 UTC, Alexander Zhirov 
wrote:
On Friday, 11 November 2022 at 00:02:09 UTC, Alexander Zhirov 
wrote:

```d
import std.algorithm;
arr = arr.remove(arr.countUntil(fragment));
```


And will this method work?

```d
A[] arr;
A fragment = new A;
...
remove(current => current == fragment)(arr);
```


And it will be even more accurate so as not to cause an error:

```d
A[] arr;
A fragment = new A;
...
arr = remove(current => current == fragment)(arr);
```


You forgot the exclamation mark. And UFCS allows you to put `arr` 
in front, making it a bit easier on the eyes:


arr = arr.remove!(current => current == fragment);


Re: DConf '22: No-Allocated 0-terminated path strings

2022-10-21 Thread ag0aep6g via Digitalmars-d-learn

On Friday, 21 October 2022 at 13:49:01 UTC, cc wrote:

```d
//version=AllowMalloc;
auto toCStringThen(alias dg, Range)(Range src) /*nothrow*/ if 
(isInputRange!Range && !isInfinite!Range) {

```

[...]
May need to be cleaned up for character types and needs to 
iterate twice if allocations are going to be allowed


Nitpick: You cannot iterate a true input range twice. You need a 
forward range for that.


Re: Find out what type my class is being converted to for comparisons

2022-10-18 Thread ag0aep6g via Digitalmars-d-learn
On Tuesday, 18 October 2022 at 18:53:41 UTC, Matthew Rushworth 
wrote:

The entirety of opEquals:

```
/// both matrices have to have an identical shape to compare
/// each element must be identical to match
bool opEquals(size_t X, size_t Y)(const Matrix!(X,Y) m1, const 
Matrix!(X,Y) m2) {
for (int i = 0; i < m1.data.length; ++i) if (m1.data[i] != 
m2.data[i]) return false;

return true;
}
```


A free-standing opEquals won't work. It needs to be a method of 
the class. So:


```d
class Matrix(size_t X, size_t Y = X)
{
/* ... */

bool opEquals(const Matrix m2)
{
for (int i = 0; i < this.data.length; ++i)
if (this.data[i] != m2.data[i]) return false;
return true;
}
}
```


Re: Example for multi level template composition

2022-10-10 Thread ag0aep6g via Digitalmars-d-learn

On Monday, 10 October 2022 at 06:30:05 UTC, Arun wrote:
Stumbled upon this question on HN 
https://news.ycombinator.com/item?id=33142751#33147401


Can I write template A and then apply it to itself to get 
template B and then apply that onto template C to get template 
D.


Does anyone have an example for this?


You can just write that down in code:

```d
template D() { enum D = "It's me, template D!"; }

template A(alias MyA)
{
template A(alias MyC)
{
alias A = D;
}
}

template C() {}

alias B = A!A;
alias MaybeD = B!C;
pragma(msg, MaybeD!()); /* prints "It's me, template D!" */
```


Re: Doubt about char.min/max == typeid(char)

2022-10-07 Thread ag0aep6g via Digitalmars-d-learn

On 07.10.22 07:06, bauss wrote:

If you don't need to assign it then you can cast it.

```
void a(int x) { ... }

a(cast(int)char.max);
```

Even though in the example above the cast isn't necessary, if you want 
to be sure a(int) is called then you must cast it, since an overload of 
char will obviously be picked.


You can also do that without a cast:

a(int(char.max));

Does the same thing of course, but it's less dangerous than casting.


Re: to delete the '\0' characters

2022-09-22 Thread ag0aep6g via Digitalmars-d-learn

On 22.09.22 13:14, ag0aep6g wrote:

On 22.09.22 12:53, Salih Dincer wrote:

[...]

```d
auto foo(string s)
{
   string r;
   foreach(c; s)
   {
 if(c > 0)
 {
   r ~= c;
 }
   }
   return r;
}
```

[...]

Here's a snippet that's a bit shorter than yours and doesn't copy the data:

     while (s.length > 0 && s[$ - 1] == '\0')
     {
     s = s[0 .. $ - 1];
     }
     return s;

But do you really want to allow embedded '\0's? I.e., should 
foo("foo\0bar\0") really resolve to "foo\0bar" and not "foo"?


Whoops. Your code actually turns "foo\0bar" into "foobar", removing the 
embedded '\0'. So my supposed alternative is wrong.


Still, you usually want to stop at the first '\0'.


Re: to delete the '\0' characters

2022-09-22 Thread ag0aep6g via Digitalmars-d-learn

On 22.09.22 12:53, Salih Dincer wrote:
Is there a more accurate way to delete the '\0' characters at the end of 
the string? I tried functions in this module: 
https://dlang.org/phobos/std_string.html


```d
auto foo(string s)
{
   string r;
   foreach(c; s)
   {
     if(c > 0)
     {
   r ~= c;
     }
   }
   return r;
}
```


I don't understand what you mean by "more accurate".

Here's a snippet that's a bit shorter than yours and doesn't copy the data:

while (s.length > 0 && s[$ - 1] == '\0')
{
s = s[0 .. $ - 1];
}
return s;

But do you really want to allow embedded '\0's? I.e., should 
foo("foo\0bar\0") really resolve to "foo\0bar" and not "foo"?


Usually, it's the first '\0' that signals the end of a string. In that 
case you better start the search at the front and stop at the first hit.


Re: Disk write in a "for" loop with RwMutex never happens

2022-08-29 Thread ag0aep6g via Digitalmars-d-learn

On Monday, 29 August 2022 at 16:21:53 UTC, ag0aep6g wrote:
You never change `pageId`. So as far as I can tell, you're 
always `seek`-ing to the same position, and you just overwrite 
the same piece of the file again and again.


Whoops. I guess I missed the point of the question there.


Re: Disk write in a "for" loop with RwMutex never happens

2022-08-29 Thread ag0aep6g via Digitalmars-d-learn

On Sunday, 28 August 2022 at 22:46:17 UTC, Gavin Ray wrote:

I've put the code, stripped to a minimal example here:
- https://ldc.godbolt.org/z/fzsx3Tnnn

[...]


But if the same code is placed inside of a `for` loop, suddenly 
no writes occur:

[...]


Does anyone know what is happening here? It's really puzzling.


Relevant pieces of the code:

```d
class DiskManager
{
void writePage(PageId pageId, ubyte[PAGE_SIZE] pageData)
{
synchronized (dbIOMutex.writer)
{
dbFile.seek(pageId * PAGE_SIZE);
dbFile.rawWrite(pageData);
}
}
}

void singleReadWrite()
{
PageId pageId = 0;

diskManager.writePage(pageId, pageData);
}

void multiReadWrite()
{
PageId pageId = 0;

foreach (i; 0 .. 10)
{
diskManager.writePage(pageId, pageData);
}
}
```

You never change `pageId`. So as far as I can tell, you're always 
`seek`-ing to the same position, and you just overwrite the same 
piece of the file again and again.


Re: Casting rules

2022-08-26 Thread ag0aep6g via Digitalmars-d-learn

On Friday, 26 August 2022 at 20:42:07 UTC, JG wrote:
Where can I find rules about casting. e.g. I assume casting 
away immutable is undefined behavior (or implementation defined 
behavior). What about casting to immutable (I would expect at 
most it only to be allowed if your type has no references e.g. 
ints okay but int[] not etc.) Casting const away (probably not 
allowed)? Casting to const (probably allowed).


Anyhow guessing aside where can I find the rules?


Casting immutable/const away: 
https://dlang.org/spec/const3.html#removing_with_cast


The cast itself allowed. Mutating the data is not.

Casting to immutable: 
https://dlang.org/spec/const3.html#creating_immutable_data


The cast is allowed as long as you don't mutate the data 
afterwards.


Conversion to const doesn't need a cast. Mutable and immutable 
both implicitly convert to const.


Re: Index an AliasSeq with a run-time index

2022-08-14 Thread ag0aep6g via Digitalmars-d-learn

On 14.08.22 12:08, Per Nordlöw wrote:

How do I index an `AliasSeq` with an integer known at run-time?


With a `switch` that has a `case` for every possible index:


import std.meta: AliasSeq;
alias seq = AliasSeq!("foo", "bar", "baz");
string f(size_t rti)
{
sw: switch (rti)
{
static foreach (cti; 0 .. seq.length)
{
case cti: return seq[cti]; break sw;
}
default: break sw;
}
return "";
}



Re: Cast converts AA to rvalue?

2022-08-10 Thread ag0aep6g via Digitalmars-d-learn

On Wednesday, 10 August 2022 at 17:14:08 UTC, Johan wrote:

```
void f() {
aa[1] = 1; // error
}
shared static this()
{
f();
}
```

I had considered it, but discarded it... `f` is also a template 
in our code. Your remark made me check again, and the call 
chain is short, perhaps I'll convert `f` to a template mixin... 
Unfortunately doesn't work: "immutable variable `aa` 
initialization is not allowed in nested function `f`".


If you can build a mutable version of the array in a `pure` 
function, you can do it like this:


```d
int[int] make_aa() pure
{
int[int] maa;
maa[1] = 1; /* or function calls, or whatever */
return maa;
}
immutable int[int] aa;
shared static this()
{
aa = make_aa();
}
```

If you can't do it in a `pure` function, you can do it with a 
cast: `aa = cast(immutable) make_aa();`.


Casting from mutable to immutable is better, because it does not 
have undefined behavior (as long as you don't use a mutable 
reference later). Your casting away immutable and then mutating 
does have undefined behavior.


Re: Cast converts AA to rvalue?

2022-08-10 Thread ag0aep6g via Digitalmars-d-learn

On 10.08.22 10:20, Johan wrote:

```
shared immutable int[int] aa;
void main () {
     // (cast()aa)[1] = 1; // works without immutable
     (*cast(int[int]*)())[1] = 1;
}
```


We have shared static constructors for that:

shared static this()
{
aa[1] = 1; /* no cast needed */
}


Re: Acess variable that was set by thread

2022-08-08 Thread ag0aep6g via Digitalmars-d-learn
On Monday, 8 August 2022 at 20:36:34 UTC, Steven Schveighoffer 
wrote:

[...]
shared gives you a sense that the language is helping you 
prevent problems. Again, if C isn't playing ball, this is a lie.


The C side is playing ball, by whatever rules the C library 
chooses.


`shared` (with `-preview=nosharedaccess`) prevents you from going 
on the field. Can't unwittingly commit a foul. Can't hurt 
yourself. You can tell the compiler with a cast that (1) you're 
sure you want to play, and (2) you're going to play by the rules 
of the C side (whatever they are).


`__gshared` just lets you run on the field. Don't know the rules? 
The compiler doesn't care. Have fun breaking your legs.


[...]
Consider if the proper way to use such a variable is to call 
`properlyUse(int *)`, it won't accept a `shared int *`. Now you 
are doubly-sure to mess up using it specifically because it's 
marked `shared`.


With `__gshared`:

```d
extern(C) extern __gshared int x;
void fun() { x = 42; } /* compiles, race condition */
```

I never even realize that I'm doing something dangerous, because 
my first naive attempt passes compilation and seems to work fine.


With `shared` (and `-preview=nosharedaccess`):

```d
extern(C) extern shared int x;
void fun() { x = 42; } /* error */
```

If I remember to check the documentation, I might find out about 
`properlyUse`. As you suggest, I come up with this:


```d
extern(C) extern shared int x;
void fun() { properlyUse(, 42); } /* still error because 
`shared` */

```

I'm forced to think more about thread-safety. I figure that it's 
ok to cast away `shared` in this case, because I'm calling the 
thread-safe `properlyUse` function. So:


```d
extern(C) extern shared int x;
void fun() { properlyUse(cast(int*) , 42); } /* compiles, is 
correct */

```

I don't believe that people are more likely to get that right 
with `__gshared`. The call to `properlyUse` might look nicer 
without the cast, but I'm not buying that people remember to use 
the function without the compiler yelling at them.


Even if they get it right the first time, they're bound to slip 
up as time progresses. When simple, incorrect code compiles, it 
will surely make its way into the source files.


Thread-safety is hard to get right. We need every help we can get 
from the compiler. `__gshared` provides zero help. `shared` at 
least highlights the interesting spots.


Re: Acess variable that was set by thread

2022-08-08 Thread ag0aep6g via Digitalmars-d-learn
On Monday, 8 August 2022 at 19:33:14 UTC, Steven Schveighoffer 
wrote:
There's nothing clever. If you want to access C globals, you 
should use `__gshared`, because that's what it is. Using 
`shared`, isn't going to save you at all.


Yes, using `shared` does save you.

C might not have a `shared` qualifier, but C programmers still 
have to think about thread-safety. Calling a C function or 
accessing a C global always comes with some (possibly implied) 
contract on how to do it safely from multiple threads (the 
contract might be: "don't").


`shared` (with `-preview=nosharedaccess`) forces you to think 
about what the contract is. `__gshared` doesn't.


[...]
Using `__gshared` to share data with C is as safe as using 
`-boundscheck=on` and sending the array into C which has no 
such restrictions.


No it's not. C always being unsafe is true but irrelevant. The 
point is what you can/can't do on the D side.


`-boundscheck=on` - Can't easily mess up on the D side. C side 
can still mess up.

`-boundscheck=off` - Can easily mess up on the D side.
`shared` - Can't easily mess up on the D side. C side can still 
mess up.

`__gshared` - Can easily mess up on the D side.


Re: Acess variable that was set by thread

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

On Monday, 8 August 2022 at 17:45:03 UTC, bauss wrote:

On Monday, 8 August 2022 at 13:55:02 UTC, ag0aep6g wrote:

auto x = s.x;
```



Your problem is here and not because it was __gshared.

You're copying the value and obviously it can be changed in the 
meantime, that's common sense.


You shouldn't use it like that. You should access s.x directly 
instead.


kdevel has already addressed this.

And in the case of shared it can leave the same result if the 
reading thread locks first then it will read and process the 
value before it's changed.


You're right that `shared` doesn't fix the race condition. 
Without `-preview=nosharedaccess`, there is no difference at all. 
So you might as well use `shared` ;)


But with `-preview=nosharedaccess`, the code no longer compiles, 
and you're forced to think about how to access the shared data 
safely. Which is good.


So: Never ever use `__gshared`, and always use 
`-preview=nosharedaccess`.


Re: Acess variable that was set by thread

2022-08-08 Thread ag0aep6g via Digitalmars-d-learn
On Monday, 8 August 2022 at 14:29:43 UTC, Steven Schveighoffer 
wrote:
C has no notion of shared, so it's not the right type. Putting 
`shared` on it is kind of lying, and can lead to trouble. 
Better to be explicit about what it is.


Nonsense. Putting `shared` on a shared variable is not "lying". 
It doesn't matter if C makes the distinction. D does.


I'm not saying you should use `__gshared` liberally, or for 
cases where you are using this only in D. But to say you should 
*never* use it is incorrect.


If you're clever enough to identify a valid use case for 
`__gshared` and write correct code with it, then you're clever 
enough to figure out when not to listen to me.


Everyone else, don't ever use `__gshared` ever.

`__gshared` is about as bad as `-boundscheck=off`. They're both 
glaring safety holes. But people want to be propper hackers (TM). 
And propper hackers know how to handle these foot-guns, of 
course. And then they shoot their feet off.


Re: Acess variable that was set by thread

2022-08-08 Thread ag0aep6g via Digitalmars-d-learn
On Monday, 8 August 2022 at 13:31:04 UTC, Steven Schveighoffer 
wrote:

On 8/8/22 6:17 AM, ag0aep6g wrote:

[...]
Never ever use `__gshared` ever. It's a glaring safety hole. 
Use `shared` instead.


If you are interfacing with C, you need __gshared. But yeah, 
you should use shared in this case.


A quick test suggests that `extern(C) extern shared` works fine.

As far as I can tell, `__gshared` is only ever ok-ish when you 
want to access a shared C variable in a single-threaded program. 
And then you're still setting yourself up for failure if you 
later add more threads.


So, never ever use `__gshared` (in multi-threaded code) ever.


Re: Acess variable that was set by thread

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

On Monday, 8 August 2022 at 12:45:20 UTC, bauss wrote:

On Monday, 8 August 2022 at 10:17:57 UTC, ag0aep6g wrote:


Never ever use `__gshared` ever.

[...]

To sum it up:

Single-write/Single-read?
__gshared

Single-write/Multi-read?
__gshared

Multi-write/Single-read?
shared

Multi-write/Multi-read?
shared


Nope. All of those can be race conditions.

Here's a single-write, single-read one:

```d
align(64) static struct S
{
align(1):
ubyte[60] off;
ulong x = 0;
}
__gshared S s;
void main()
{
import core.thread: Thread;
import std.conv: to;
new Thread(() {
foreach (i; 0 .. uint.max)
{
s.x = 0;
s.x = -1;
}
}).start();
foreach (i; 0 .. uint.max)
{
auto x = s.x;
assert(x == 0 || x == -1, to!string(x, 16));
}
}
```

If you know how to access the variable safely, you can do it with 
`shared`.


I maintain: Never ever use `__gshared` ever.


Re: Acess variable that was set by thread

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

On Monday, 8 August 2022 at 07:14:33 UTC, vc wrote:

it seems change it to working is working

```d
 __gshared bool zeus;
 ```

but as I'm new in to D, i will like to hear thoughts even if it 
works for me


Never ever use `__gshared` ever. It's a glaring safety hole. Use 
`shared` instead.


If you're running into compilation errors with `shared`, that's 
the compiler trying to keep you from shooting your foot off. 
You're supposed to think hard about thread-safety and only then 
cast `shared` away in the right spot.


With `__gshared`, the compiler just pretends that it doesn't see 
that the variable is shared. You're pretty much guaranteed to 
produce race conditions unless you think even harder than you 
would have with `shared`.


By the way, is there some resource that recommends `__gshared` 
over `shared`? It seems that many newbies reach for `__gshared` 
first for some reason.


Re: Ranges

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

On Sunday, 7 August 2022 at 15:34:19 UTC, pascal111 wrote:
Everyone knows that slices are not pointers that pointers are 
real work, but slices are like a simple un-deep technique that 
is appropriate for beginners, but after that in advanced level 
in programming, we should use pointers to do same tasks we were 
doing with slices (the easy way of beginners).


I can't tell if this is a joke or not.


Re: Breaking ";" rule with lambda functions

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

On Monday, 1 August 2022 at 15:52:34 UTC, pascal111 wrote:
But how can we accept that both are functions and expressions 
at the same time and we know that expressions can be used to 
build functions themselves?!! I think they are not the same.


This is getting ridiculous. I'm out.


Re: Breaking ";" rule with lambda functions

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

On Monday, 1 August 2022 at 15:31:51 UTC, pascal111 wrote:
Surely, because it seems that you are real man, your word must 
be taken. Isn't `(foo) { return bar; }` an anonymous function 
or am I a wrong?!! It IS a function, not an expression.


It's both an anonymous function and an expression. I don't know 
why you think it can't be both.


Re: Breaking ";" rule with lambda functions

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

On Monday, 1 August 2022 at 14:52:03 UTC, pascal111 wrote:
If `foo => bar` == `(foo) { return bar; }`, then  `foo => bar` 
is a function. "=>" is not an operator, it's a special symbol 
for lambda "function".


If A == B, so A's types is the same of B's type. How can it be 
withstanding `foo => bar` == `foo => bar` == `(foo) { return 
bar; }` and `foo => bar` is an expression and the other is a 
function?!! no sense.


`foo => bar` and `(foo) { return bar; }` are both function 
literals, and they're both expressions. The concepts are not 
mutually exclusive.


Re: Breaking ";" rule with lambda functions

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

On Monday, 1 August 2022 at 14:39:17 UTC, pascal111 wrote:

On Monday, 1 August 2022 at 14:34:45 UTC, ag0aep6g wrote:

[...]

`a => a > 0` is not a statement. It's an expression.


But it is still a "function", and functions make statements!! 
It's not a normal expression.


It's a normal expression.

`foo => bar` is an expression that doesn't involve any statement. 
So there's no semicolon.


`(foo) { return bar; }` does contain a return statement. As you 
expect, there's a semicolon. But it's still an expression like 
any other.


Re: Breaking ";" rule with lambda functions

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

On Monday, 1 August 2022 at 14:15:31 UTC, pascal111 wrote:
Many of D rules are taken from C, we know that, so a general 
basic rule is to put ";" after each statement, so the previous 
statement of filter should be "auto r = chain(a, b).filter!(a 
=> a > 0;);"? Why D leaves ";" in this case?


`a => a > 0` is not a statement. It's an expression.


Re: Is this a violation of const?

2022-07-30 Thread ag0aep6g via Digitalmars-d-learn

On 30.07.22 09:15, Salih Dincer wrote:
It's possible to do this because it's immutable.  You don't need an 
extra update() function anyway.


```d
void main()
{
     auto s = S("test A");
     s.update = (_) { s.s = _; };

     s.update("test B");
     assert(s.s == "test B");

     s.s = "test C";
     assert(s.s == "test C");
} // No compile error...
```


You're not making sense. Your `s` is mutable, not immutable.


Re: Is this a violation of const?

2022-07-30 Thread ag0aep6g via Digitalmars-d-learn

On 29.07.22 23:56, Andrey Zherikov wrote:
In the example below `func` changes its `const*` argument. Does this 
violates D's constness?


Yes. Here's a modified example to show that you can also violate 
`immutable` this way:


struct S
{
string s;
void delegate(string s) @safe update;
}

S* makeS() pure @safe
{
auto s = new S("test");
s.update = (_) { s.s = _; };
return s;
}

void main() @safe
{
immutable S* s = makeS();
assert(s.s == "test"); /* passes */
s.update("func");
auto ss = s.s;
assert(ss == "test"); /* fails; immutable data has changed */
}


Re: char* pointers between C and D

2022-07-25 Thread ag0aep6g via Digitalmars-d-learn

On Monday, 25 July 2022 at 11:14:56 UTC, pascal111 wrote:

module main;

import std.stdio;
import core.stdc.stdio;
import core.stdc.string;

int main(string[] args)
{


const(char)[] ch1 = "Hello World!";
char[] ch2="Hello World!".dup;

const(char) *p1;
char *p2;

p1=ch1.ptr;
p2=ch2.ptr;

writeln(p1[0..strlen(p1)]);
writeln(p2[0..strlen(p2)]);

return 0;
}


Runtime output:

https://i.postimg.cc/sfnkJ4GM/Screenshot-from-2022-07-25-13-12-03.png


Do not post screenshots of text.

`strlen` only works on null-terminated strings. The result of 
`.dup` is not null-terminated, so `strlen` doesn't work on it.


Re: Working with arrays (flatten, transpose, verfify rectangular)

2022-07-20 Thread ag0aep6g via Digitalmars-d-learn

On 20.07.22 11:18, anonymouse wrote:

     d
     auto isRectangular(A)(A a) if (isArray!A)
     {
     bool result;
     size_t length = a[0].length;

     foreach (e; a) {
     result = e.length == length;
     }
     return result;
     }
     

This only works if a is a 2D array, how do I extend this to 
support arrays with larger dimensions (3D, 4D, 5D, etc.)?


(Aside: You don't need that many backticks to mark code fragments.)

You've got a bug there. This should pass, but fails with your version:

assert(!isRectangular([[1, 2], [], [3, 4]]));

Once `result` becomes false, you cannot let it switch to true again.

As for generalizing the function, instead of comparing the lengths of 
the elements, you want to compare their "shapes". The shape of a `Foo[] 
a1;` is `[a1.length]`. The shape of a rectangular `Foo[][] a2;` is 
`[a2.length, a2[0].length]`. And so on.


Start by extending `isRectangular` to also (optionally) return the shape 
of the array:


bool isRectangular(A)(A a) if (isArray!A)
{
size_t[] dummy;
return isRectangular(a, dummy);
}
bool isRectangular(A)(A a, out size_t[] shape) if (isArray!A)
{
size_t first_length = a[0].length;
foreach (e; a)
{
if (e.length != first_length) return false;
}
shape = [a.length, first_length];
return true;
}
unittest
{
size_t[] shape;
assert(isRectangular([[1, 2], [3, 4], [5, 6]], shape));
assert(shape == [3, 2]);
assert(!isRectangular([[1, 2], [], [3, 4]]));
}

Extend it to one-dimensional arrays:

bool isRectangular(A)(A a, out size_t[] shape) if (isArray!A)
{
shape = [a.length];
alias E = typeof(a[0]);
static if (isArray!E)
{
size_t first_length = a[0].length;
shape ~= first_length;
foreach (e; a)
{
if (e.length != first_length) return false;
}
}
return true;
}
unittest /* one dimension */
{
size_t[] shape;
assert(isRectangular([1, 2, 3], shape));
assert(shape == [3]);
}

Finally, use the magic of recursion to conquer higher dimensions:

bool isRectangular(A)(A a, out size_t[] shape) if (isArray!A)
{
shape = [a.length];
alias E = typeof(a[0]);
static if (isArray!E)
{
size_t[] first_shape;
if (!isRectangular(a[0], first_shape)) return false;
shape ~= first_shape;
foreach (e; a)
{
size_t[] e_shape;
if (!isRectangular(e, e_shape)) return false;
if (e_shape != first_shape) return false;
}
}
return true;
}
unittest /* higher dimensions */
{
size_t[] shape;
assert(isRectangular([
[[ 1,  2,  3,  4], [ 5,  6,  7,  8], [ 9, 10, 11, 12]],
[[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24]]
], shape));
assert(shape == [2, 3, 4]);
}

I'm sure the function can be improved further, but I'm not going to get 
into that.


For task 3, I can visit each element of the array, but I have no idea 
how to compose the flattened (1D) version:


     d
     import std.range.primitives: ElementType;
     auto flatten(A)(A a) if (isArray!A)
     {
     //ElementType!(A)[] result; //[1]
     foreach (i; a) {
     static if (isArray!(typeof(i)))
    flatten(i);
     else {
     writeln(i);
     // result ~= i; //[2]
     }
     }
     //return result; // [3]
     }
     


You've got the right idea there with `flatten` calling itself on each 
element. You only need to apply that idea when getting the element type, 
too (and actually append the result of the recursive call to `result`):


import std.range.primitives: ElementType;
template FlatElementType(A) if (isArray!A)
{
alias E = ElementType!A;
static if (isArray!E)
{
alias FlatElementType = FlatElementType!E;
}
else
{
alias FlatElementType = E;
}
}
unittest
{
static assert(is(FlatElementType!(int[]) == int));
static assert(is(FlatElementType!(int[][]) == int));
static assert(is(FlatElementType!(int[][][]) == int));
}
auto flatten(A)(A a) if (isArray!A)
{
FlatElementType!A[] result;
foreach (i; a)
{
static if (isArray!(typeof(i)))
result ~= flatten(i);
else
result ~= i;
}
return result;
   

Re: null == "" is true?

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

On 12.07.22 22:14, H. S. Teoh wrote:

Pedantically, no, they're not the same. You can assign null to a
pointer, but you can't assign [] to a pointer. `null` is a supertype of
`[]`.

But probably nobody actually cares about this distinction. :-D


If we're ignoring context, "null" has four characters, while "[]" has 
only two. Clearly, they're not similar at all.


The context was arrays, not pointers. `void f(T[] a = null) {}` has 
exactly the same meaning as `void f(T[] a = []) {}`.


Re: null == "" is true?

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

On Tuesday, 12 July 2022 at 19:02:01 UTC, user1234 wrote:

On Tuesday, 12 July 2022 at 16:40:38 UTC, H. S. Teoh wrote:

[...]

Do not rely on this, however;


Absolutely. I'd like to add: especially as default parameter 
value that's an array. Never use null. use `[]` (empty array 
literal).


Just to be clear: `[]` and `null` are the exact same thing (null 
pointer, zero length). The reason to prefer `[]` over `null` is 
purely for readability. The meaning is exactly the same.


Re: How can I match every instance of a template type (struct)?

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

On Tuesday, 12 July 2022 at 13:56:11 UTC, rempas wrote:

On Tuesday, 12 July 2022 at 13:37:49 UTC, ag0aep6g wrote:


static if (is(typeof(obj) == Test!T, T)) { 
printf("YES!!!\n"); }


Haah? Ok, what does this work anyway? I thought you needed 
parenthesis for more than 1 templated arguments...


The second `T` is not a template argument. It's an operand of the 
"IsExpression".


You can read more about those expressions here:
https://dlang.org/spec/expression.html#is-parameter-list


Re: How can I match every instance of a template type (struct)?

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

On 12.07.22 15:34, rempas wrote:

extern (C) void main() {
   auto obj = make_test(20);
   static if (is(typeof(obj) == Test)) { printf("YES!!!\n"); }
}


static if (is(typeof(obj) == Test!T, T)) { printf("YES!!!\n"); }


Re: Cannot copy void[] to void[] in @safe code?

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

On Friday, 8 July 2022 at 10:58:24 UTC, wjoe wrote:
My understanding is that a void[] doesn't have a distinct type 
but since the length is bytes and not elements this makes me 
believe that under the hood they are byte arrays - or, rather, 
managed chunks of memory.
How's copying memory without a distinct type different from 
copying, say, an ubyte[] to an ubyte[] ?


You're allowed to copy from `ubyte[]` to `ubyte[]`. But you're 
not allowed to copy from `ubyte[]` to `int*[]`, because 
reinterpreting a bunch of bytes as pointers is not safe.


The thing about `void[]` is that it can point to memory that also 
has a typed alias. You can have a `void[]` and a `ubyte[]` 
pointing to the same memory. And you can have a `void[]` and an 
`int*[]` pointing to the same memory. So if you were allowed to 
copy from `void[]` to `void[]`, you'd practically be allowed to 
copy from `ubyte[]` to `int*[]`. But that's not safe.


In code:

```d
void main() @safe
{
ubyte[] some_bytes = [1, 2, 3, 4, 5, 6, 7, 8];
int*[] some_pointers = [new int];
void[] v1 = some_bytes;
void[] v2 = some_pointers;
v2[] = v1[]; /* creating invalid pointers */
int x = *some_pointers[0]; /* undefined behavior */
}
```


Re: DIP1000

2022-06-23 Thread ag0aep6g via Digitalmars-d-learn
On Thursday, 23 June 2022 at 20:27:44 UTC, Ola Fosheim Grøstad 
wrote:

On Thursday, 23 June 2022 at 19:38:12 UTC, ag0aep6g wrote:

```d
void connect(ref scope node a, return scope node* b)
```


Thanks, so the `return scope` means «allow escape», not 
necessarily return?


It means "may be returned or copied to the first parameter" 
(https://dlang.org/spec/function.html#param-storage). You cannot 
escape via other parameters. It's a weird rule for sure.


Re: DIP1000

2022-06-23 Thread ag0aep6g via Digitalmars-d-learn
On Thursday, 23 June 2022 at 16:08:01 UTC, Ola Fosheim Grøstad 
wrote:

How am I supposed to write this:

```d
import std;
@safe:

struct node {
node* next;
}

auto connect(scope node* a, scope node* b)
{
a.next = b;
}

void main()
{
node x;
node y;
connect(,);
}

```


Error: scope variable `b` assigned to non-scope `(*a).next`


DMD accepts this:

```d
@safe:

struct node {
node* next;
}

void connect(ref scope node a, return scope node* b)
{
a.next = b;
}

void main()
{
node y;
scope node x;
connect(x, );
}
```

But that only works for this very special case. It falls apart 
when you try to add a third node. As far as I understand, `scope` 
cannot handle linked lists. A `scope` pointer cannot point to 
another `scope` pointer.


So as to how you're supposed to do it: with @system.


Re: want to confirm: gc will not free a non-gc-allocated field of a gc-allocated object?

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

On 07.06.22 11:00, max haughton wrote:

On Tuesday, 7 June 2022 at 08:56:29 UTC, ag0aep6g wrote:

[...]

That wasn't mw's question.


I also answered this in my original one IIRC.


You didn't.


Re: want to confirm: gc will not free a non-gc-allocated field of a gc-allocated object?

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

On 07.06.22 03:02, max haughton wrote:

I'm talking about the data in the array.

void[] might contain pointers, float[] does not so it won't be scanned.


That wasn't mw's question.


Re: want to confirm: gc will not free a non-gc-allocated field of a gc-allocated object?

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

On 07.06.22 00:22, max haughton wrote:
float[] doesn't contain pointers, so the GC won't do anything to or with 
it.


wat

float[] is a pointer (plus a length). The GC will deal with it like any 
other pointer.


Re: template? mixin? template mixins? for modifying a struct setup

2022-05-19 Thread ag0aep6g via Digitalmars-d-learn

On 19.05.22 12:15, Chris Katko wrote:

given
```D
struct COLOR
{
float r, g, b, a; // a is alpha (opposite of transparency)
}

auto red   = COLOR(1,0,0,1);
auto green = COLOR(0,1,0,1);
auto blue  = COLOR(0,0,1,1);
auto white = COLOR(1,1,1,1);
//etc
```

is there a way to do:
```D
auto myColor = GREY!(0.5);
// where GREY!(0.5) becomes COLOR(0.5, 0.5, 0.5, 1.0);
```


What's wrong with a simple plain function?

COLOR grey(float rgb)
{
return COLOR(rgb, rgb, rgb, 1);
}
auto myColor = grey(0.5);


Re: Creating a custom iota()

2022-05-12 Thread ag0aep6g via Digitalmars-d-learn

On Thursday, 12 May 2022 at 17:06:39 UTC, Ali Çehreli wrote:

void main() {
  const st = DateTime(Duration(0));

[...]


  // (0) I think D should not insist on 'const'
  // when copying types that have no indirections.
  // We shouldn't need the cast() below in this case.

[...]

  iota(cast()st, en, step).each!writeln;
}


[...]

auto iota(B, E, S)(B begin, E end, S step)

[...]

{
static struct Result
{
B current;

[...]

void popFront()
{

[...]

current += step;
}
}

[...]

}


Mark iota's `begin` parameter as const. Then you don't need the 
cast, because `B` will be mutable.


Re: Trait for "can be instantiated"?

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

On 09.05.22 23:24, Ben Jones wrote:

enum x;
enum y = 5;

struct Wrap(alias T) {
     static if(isType!T){
  T value; //When t == x this doesn't work because `x` is opaque 
and has no default initializer

     }
}

[...]


x is a "type" as far as isType is concerned (which makes sense to me), 
but I don't think you can ever declare a variable of that type since 
there's no way to initialize it... Is there a trait that can tell if you 
can initialize a variable of a certain type?  The best I can think of is 
__traits(compiles, "T x;"), but it seems like it should be possible to 
do better?


`x` is a type, period.

You can use void initialization to declare values of types that don't 
have an `init` value: `x value = void;`


As for an alternative to the brute force `__traits(compiles, ...)`, you 
can check if `T.init` is a thing:


static if (is(typeof(T.init))) { T value; }

I'm not sure if that's really better, though.

By the way, what is your `Wrap` supposed to do with `x`? Treating it 
like `y` will likely fail, too, because `x` is not a value.


Re: Parameters declared as the alias of a template won't accept the arguments of the same type.

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

On 02.05.22 22:47, Stanislav Blinov wrote:

On Monday, 2 May 2022 at 20:16:04 UTC, ag0aep6g wrote:

On 02.05.22 21:17, Stanislav Blinov wrote:

On Monday, 2 May 2022 at 16:29:05 UTC, Loara wrote:

[...]

```d
    template MyAlias(T){
  alias MyAlias = int;
    }

    T simp(T)(MyAlias!T val){
  return T.init;
    }

    int main(){
  simp(3);//Impossible to deduce T

[...]
That's not my answer. And it is nonsense, because my answer is - what T 
is irrelevant, MyAlias maps *all* types to int. Therefore `simp` takes 
an int, which is what the caller is passing.


And what does it return?


Re: Parameters declared as the alias of a template won't accept the arguments of the same type.

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

On 02.05.22 21:17, Stanislav Blinov wrote:

On Monday, 2 May 2022 at 16:29:05 UTC, Loara wrote:

[...]

```d
    template MyAlias(T){
  alias MyAlias = int;
    }

    T simp(T)(MyAlias!T val){
  return T.init;
    }

    int main(){
  simp(3);//Impossible to deduce T


Why? That's the issue. It is very possible to deduce T here. Compiler 
just isn't trying. The function takes an int. Doesn't take a rocket 
scientist to figure that one out.


I take it your answer is that T must be int. But that's nonsense. 
MyAlias maps all types to int. It's not a bijection, you can't turn it 
around.


Re: stack frame & dangling pointer weirdness

2022-04-21 Thread ag0aep6g via Digitalmars-d-learn

On 21.04.22 13:25, Alain De Vos wrote:

How can i force an error to be thrown when doing something "bad" ?


Use @safe.


Re: stack frame & dangling pointer weirdness

2022-04-21 Thread ag0aep6g via Digitalmars-d-learn

On 21.04.22 07:49, Alain De Vos wrote:

int *p=null;
void myfun(){
 int x=2;
 p=
 writeln(p);
 writeln(x);
}
myfun();
*p=16;
writeln(p);
writeln(*p);


`p` is no longer valid after `myfun` returns. Dereferencing it is an error.

The two `writeln` calls in `main` re-use the memory that `p` points to 
for their own purposes.


Re: Why do immutable variables need reference counting?

2022-04-17 Thread ag0aep6g via Digitalmars-d-learn

On 17.04.22 15:27, H. S. Teoh wrote:

On Sun, Apr 17, 2022 at 01:06:36PM +, wjoe via Digitalmars-d-learn wrote:
[...]

On the matter of undefined behavior. Technically a program is in
undefined behavior land after throwing an error, thus every unittest
that continues after assertThrown is therefore nonsense code, is it
not ?


The spec explicitly makes an exception(!) in this case. See 10.24.11.3:

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

as well as 27.3:

https://dlang.org/spec/unittest.html


But the failing assert is not part of the unittest directly. It's in a 
function that is called from the unittest. It takes a generous 
interpretation of the spec to include such asserts in the exception.


Letting failing asserts cause UB is a mistake anyway. It stems from a 
misguided desire to re-use asserts for optimization, when nobody 
actually uses them that way.


Re: Why do immutable variables need reference counting?

2022-04-17 Thread ag0aep6g via Digitalmars-d-learn

On 17.04.22 15:06, wjoe wrote:
On the matter of undefined behavior. Technically a program is in 
undefined behavior land after throwing an error, thus every unittest 
that continues after assertThrown is therefore nonsense code, is it not ?


Yes.

Failing asserts are a messy part of the language. They are supposed to be:

1) not catchable, because they indicate a bug in the program;
2) catchable in order to be testable;
3) assumed impossible for optimization purposes.

Those goals are at odds with each other, and I don't think the spec 
manages to consolidate them.


But mutating `immutable` data is not messy. It's simply not allowed.


Re: Why do immutable variables need reference counting?

2022-04-14 Thread ag0aep6g via Digitalmars-d-learn

On 14.04.22 13:42, wjoe wrote:
Undefined behavior yes, but regardless the example proves it can be done 
in @system code.
A few versions ago, possibly due to a bug or regression, the compiler 
didn't complain in @safe code either.


Of course you are correct academically. However, since it's possible, 
I'd wager my last hat that code like this is out in the wild.


No, it cannot be done in @system code. The example only proves that you 
can write nonsense code that has no defined meaning.


Note that the nonsense you wrote behaves as you describe only in 
Windows. Elsewhere, you get a segfault.


But it doesn't matter how the executable actually behaves. You cannot 
cite the result of undefined behavior when arguing language semantics.


Re: Why do immutable variables need reference counting?

2022-04-12 Thread ag0aep6g via Digitalmars-d-learn

On Tuesday, 12 April 2022 at 19:54:13 UTC, wjoe wrote:
Especially since it's only a promise and the compiler accepts 
this:


void foo (const(char)[] arr)
{
  cast(char[])arr[0..3] = "baz";
}
string bar = "123";
foo(bar);
assert(bar=="baz");

But I could cast away const and modify the string bar.


No, you could not. You're relying on undefined behavior there. 
Just because the compiler accepts something, doesn't mean it's ok.


If you want to be guarded against wandering into undefined 
territory, that's what @safe does. With @safe, the cast doesn't 
compile.


Re: How to remove all characters from a string, except the integers?

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

On Friday, 4 March 2022 at 19:51:44 UTC, matheus wrote:

import std.datetime.stopwatch;
import std.stdio: write, writeln, writef, writefln;
import std;

void printStrTim(string s,StopWatch sw){
writeln("\nstr: ", s
,"\nTim(ms): ", sw.peek.total!"msecs"
,"\nTim(us): ", sw.peek.total!"usecs"
   );
}

void main(){
auto sw = StopWatch(AutoStart.no);
string s, str = "4A0B1de!2C9~6";
int j;

sw.start();
for(j=0;j<1_000_000;++j){
s="";
foreach(i;str){
(i >= '0' && i <= '9') ? s~=i : null;
}
}
sw.stop();
printStrTim(s,sw);

s = "";
sw.reset();
sw.start();
for(j=0;j<1_000_000;++j){
s="";
s = str.filter!(ch => ch.isDigit).to!string;
}
sw.stop();
printStrTim(s,sw);
}

Prints:

str: 401296
Tim(ms): 306
Tim(us): 306653

str: 401296
Tim(ms): 1112
Tim(us): 1112648

---

Unless I did something wrong (If anything please tell).


The second version involves auto-decoding, which isn't actually 
needed. You can work around it with `str.byCodeUnit.filter!...`. 
On my machine, times become the same then.


Typical output:

str: 401296
Tim(ms): 138
Tim(us): 138505

str: 401296
Tim(ms): 137
Tim(us): 137376



Re: split Error - no overload matches

2022-02-14 Thread ag0aep6g via Digitalmars-d-learn

On 14.02.22 12:14, forkit wrote:

However, if I uncomment the //import std.uni : isWhite;

then it will compile.

I don't understand. I thought 'import std;' would be sufficient here??


"isWhite" is ambiguous. There's std.uni.isWhite and std.ascii.isWhite. 
`import std;` can't know which one you want.


Re: how to handle very large array?

2022-02-09 Thread ag0aep6g via Digitalmars-d-learn

On 09.02.22 11:09, MichaelBi wrote:

On Wednesday, 9 February 2022 at 10:05:23 UTC, MichaelBi wrote:

[...]

got outofmemory error:
core.exception.OutOfMemoryError@src\core\lifetime.d(126): Memory 
allocation failed


https://adventofcode.com/2021/day/6#part2

"Suppose the lanternfish live forever and have unlimited food and space. 
Would they take over the entire ocean?


After 256 days in the example above, there would be a total of 
26984457539 lanternfish!


How many lanternfish would there be after 256 days"

26984457539 in above is the array length.


If you store one byte per lanternfish, that's 25 GiB. You don't seem to 
have enough RAM for such a large array.


Try to think of a more efficient way of storing the information.


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.


  1   2   3   4   5   6   7   8   >