Re: How is opEquals used in toHash

2021-05-18 Thread Simen Kjærås via Digitalmars-d-learn

On Tuesday, 18 May 2021 at 10:14:26 UTC, PinDPlugga wrote:
But what I do not understand is why opEquals is necessary and 
where in the implementation of toHash it plays its role? Since 
area1 and area2 have different static arrays of Points I 
understand why `typeid(points).getHash()` would produce 
different values for each, but it seems like the opEquals 
should play a part in making them produce the same hash.


opEquals plays no part in how toHash does its thing, but it's 
important for how AAs work. When there's a hash collision, the 
colliding items are placed in a bucket, which is generally 
iterated linearly to find the matching element, using opEquals. 
Example code:


```d
struct S {
int i;
size_t toHash() const nothrow @safe { return 3; }
bool opEquals(ref const S rhs) const { return i == rhs.i; 
}

}

unittest {
int[S] a;
a[S(1)] = 3;
a[S(2)] = 4; // Hash collision - both return 3
assert(a.length == 2); // But they're both there
assert(S(1) in a);
assert(S(2) in a);
int b = a[S(1)];
int c = a[S(2)];
assert(b == 3);
assert(c == 4);
}
```

And pseudocode for how an AA works:

```d
struct AA(K, V) {
import std.typecons : Tuple;
alias Pair = Tuple!(K, "key", V, "value");
alias Bucket = Pair[];

Bucket[] buckets;

this(int bucketCount) {
buckets.length = bucketCount;
}

void opIndexAssign(V value, K key) {
// Use hash to find correct bucket
size_t hash = key.toHash();
size_t index = hash % buckets.length;
Bucket bucket = buckets[index];

foreach (e; bucket) {
if (e.key == key) { // Check for duplicates with 
opEquals

 e.value = value; // Overwrite existing
 return;
}
}

bucket ~= Pair(key, value);
// Array could reallocate when appended to,
// so assign it back to the bucket list
buckets[index] = bucket;
}

V opIndex(K key) {
// Use hash to find correct bucket
size_t hash = key.toHash();
size_t index = hash % buckets.length;
Bucket bucket = buckets[index];

foreach (e; bucket) {
if (e.key == key) { // Check with opEquals
return e.value;
}
}
throw new Exception("Key not found");
}
}

unittest {
AA!(S, int) a = AA!(S, int)(24);
a[S(1)] = 3;
a[S(2)] = 4;
assert(a[S(1)] == 3);
assert(a[S(2)] == 4);
}
```

This omits plenty of details, but should give some idea how AAs 
work.


--
  Simen


Re: type of functions

2021-05-10 Thread Simen Kjærås via Digitalmars-d-learn

On Monday, 10 May 2021 at 10:37:51 UTC, Alain De Vos wrote:
Can I say that the compiler is intelligent enough to add the 
attributes "pure nothrow @nogc @safe" ?


Yes, in those cases (and some others). The functionality is 
described here:

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

--
  Simen


Re: Dlang equivalent of #define/#ifdef : not... version

2021-04-20 Thread Simen Kjærås via Digitalmars-d-learn

On Tuesday, 20 April 2021 at 18:57:46 UTC, ichneumwn wrote:

So my questions:
- is there a module-crossing equivalent of "version"?


mw covered this. There's more documentation here: 
https://dlang.org/spec/version.html#version

https://dlang.org/dmd-windows.html#switch-version


- if not, is there some way I could test for the existence of 
the enum can_i_test_for_this? A SymbolExists!() or 
ModuleHasSymbol!() or ModuleHasMember!() ?


__traits(hasMember, features, "i_am_not_a_feature")

This is actually what std.traits.hasMember does, but for some 
reason it can't take a module as its first argument.


--
  Simen


Re: How can I allocate a int[] array on stack?

2021-03-26 Thread Simen Kjærås via Digitalmars-d-learn

On Friday, 26 March 2021 at 14:27:58 UTC, Jack wrote:

On Friday, 26 March 2021 at 06:45:39 UTC, Daniel Kozak wrote:
On Fri, Mar 26, 2021 at 7:36 AM Daniel Kozak 
 wrote:


On Fri, Mar 26, 2021 at 7:31 AM Daniel Kozak 
 wrote:


On Fri, Mar 26, 2021 at 6:50 AM Jack via Digitalmars-d-learn 
< digitalmars-d-learn@puremagic.com> wrote:


What's the equivalent of C's VLA in D? scoped from 
std.typecons doesn't seem to work with arrays. Should I use 
alloca() for my array or is there something else?




https://dlang.org/library/std/array/static_array.html


Sorry I was misread this



You can use allocator:

import std.experimental.allocator.showcase;
import std.experimental.allocator;
import std.stdio;

StackFront!4096 stackAlloc;

void main() {
int[] a = stackAlloc.makeArray!int(2);
writeln(a);
}


I thought this was going to use alloca() but it seems to be 
using malloc() internally?


Basically, StackFront is an allocator that allows any size 
allocation, but prefers to put things in its memory block on the 
stack. If there's no space left on the stack, it puts things on 
the heap. Not quite what you're asking for, in other words.


StackFront is basically this:

struct StackFront(size_t size) {
ubyte[size] memory;
size_t used;
T allocate(T)() {
 if (used + T.sizeof > size) return 
*cast(T*)malloc(T.sizeof);


 auto result = *cast(T*)[used];
 used += T.sizeof;
 return result;
}
}

With more bells and whistles, but it's a fixed-size block of 
memory on the stack that falls back to heap allocation when 
there's no more room in the block.


alloca is probably your best bet if you need dynamic-size stack 
allocation. That said, it's a "you're on your own" kind of 
solution. Use it if you know it's the best solution for your 
problem.


--
  Simen


Re: Opaque type (struct) with a static immutable fails to compile without constructor - why?

2021-03-04 Thread Simen Kjærås via Digitalmars-d-learn

On Thursday, 4 March 2021 at 13:58:48 UTC, frankp wrote:

Hi all,

I want to make an opaque type that simply contains an integer 
with some immutable constants and toString pretty printing. 
Like this:


struct Foo_t
{
   private long foo;
   alias foo this;
   static immutable long Inf = long.max; //1)

   void toString(...){}
}

On dmd 2.092.1 this fails with:
  1) Error: cannot implicitly convert expression 9223...L of 
type immutable(long) to Foo_t


I simply want to initialize an immutable long with long.max.
Why the conversion to Foo_t ?

If I add a constructor:
private this(long f)
{
   foo = f;
}

It compiles but according to code coverage this constructor is 
never called.

What's going on?


I tried compiling your code locally on DMD 2.094.1, and had no 
issues. Again with 2.095.0, no issues. On run.dlang.io, with all 
dmd compilers from 2.060, and it just plain works.


Now, that's after removing ... from toString. With that present, 
it fails with some variation of 'Error: undefined identifier 
'__va_list_tag''.


Most likely, you have shortened your program for clarity, and 
removed the issue you're experiencing in the process. Can we have 
another one, with the issue still there?


--
  Simen


Re: Templated delegate as template argument for structs

2021-02-20 Thread Simen Kjærås via Digitalmars-d-learn
On Saturday, 20 February 2021 at 09:16:46 UTC, Simon van Bernem 
wrote:

I have the following struct declaration:

struct Hash_Table(Key, Value, u32 delegate(ref Key) 
custom_hash_function = null)

[snip]
I take it from the error that the problem is not actually the 
delegate that I am passing, but the fact that the delegate type 
has another template parameter as the argument type. Can 
template arguments in D not reference previous template 
arguments? Is there some way I can get around this?


The D way would be an alias parameter:

struct Hash_Table(Key, Value, alias custom_hash_function) {
// ...
}

Probably also adding a constraint:

struct Hash_Table(Key, Value, alias custom_hash_function)
if (is_valid_hash_function!(Key, custom_hash_function))
{
// ...
}

// Check if the hash function can be called with a Key
// as argument, and the result be assigned to a u32
enum is_valid_hash_function(Key, alias fn) = __traits(compiles, 
(Key k){ u32 u = fn(k); });



D lets you refer to other template parameters in the same 
template parameter list in three cases, as far as I know:


1) A type may be a subtype of an earlier parameter:

class C {}
struct S(TBase, TDerived : TBase) {}
S!(Object, C) a;


2) A type parameter with a type specialization followed by 
template parameter list:


struct Fn(U) {}
struct S(T: Fn!Arg, Arg) {}
S!(Fn!int) a;


3) Following a type parameter, a value parameter of that type may 
appear:


struct S(T, T value) {}
S!(int, 4) a;


The first two can also be combined:

struct Fn(U) {}
struct S(T1, T2: Fn!T3, T3 : T1) {}
S!(int, Fn!int) a;


However, it seems 3) only works with that specific type, modulo 
storage classes. No Foo!T, no void delegate(T). At any rate, the 
alias parameter is the way it's generally done, and is more 
flexible, so just leave it at that.


--
  Simen


Re: Creating 1000 instances

2021-02-19 Thread Simen Kjærås via Digitalmars-d-learn

On Friday, 19 February 2021 at 10:02:05 UTC, Siemargl wrote:
On Friday, 19 February 2021 at 08:29:36 UTC, Ferhat Kurtulmuş 
wrote:


Since classes are reference types all instances of files will 
be the same reference of "new File()", which you probably 
don't want.


Is any differences between x and y definitions?

MyClass [] x, y;
x = new MyClass[7];

y= new MyClass[](8);


The only part of the documentation I've found that talks about 
this is here:

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

The main difference I know of comes with multidimensional arrays:

auto a = new int[4][4];
pragma(msg, typeof(a)); // Prints int[4][]
auto b = new int[][](4,4);
pragma(msg, typeof(b)); // Prints int[][]

Since the former is a dynamic array of static arrays, the first 
size parameter cannot be passed at runtime:


auto n = 4;
// Error: variable n cannot be read at compile time
auto c = new int[n][n];

But must be a compiletime constant:

enum N = 4;
auto d = new int[N][n];
pragma(msg, typeof(d)); // Prints int[4][]

The other syntax however, can take runtime values, but does not 
encode the size in the type:


auto e = new int[][](n,n);
pragma(msg, typeof(e)); // Prints int[][]

The other big thing about the []() syntax is it actually 
initializes the arrays of arrays for you:


assert(e[0].length == n);

If you were to use new int[][n], you would need to initialize 
each array of arrays manually:


auto f = new int[][n];
assert(f[0].length == 0); // it's empty
foreach (i; 0..n) {
f[i] = new int[n]; // Have to do this yourself.
}

--
  Simen


Re: Two "references" to dynamic array, why not change both when reallocating?

2020-11-11 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 11 November 2020 at 10:17:09 UTC, zack wrote:
I am new to D. Appending to an array can lead to reallocation, 
that's clear. But why is the "reference" b not changed 
accordingly to the new position and still points to "old" 
memory? Why is b not also changed when reallocating array a and 
the old data getting invalid/freed?


auto a = [55,10,20];
auto b = a;
a ~= [99,99,99,99,99,99];
a[0] = 1;
assert(b[0] == 1); // could fail

(similar to p.103-104 in "The D Programming language")


The short answer is 'because that's how we've chosen to define 
it'. A more involved answer is that changing every reference is 
prohibitively expensive - it would require the equivalent of a GC 
collection on every reallocation, as references to the array 
could exist anywhere in the program, be that on the stack, heap, 
even on other threads. That's the performance side of it.


Another heavy argument is 'can you make it behave the other way?' 
Currently, that's simple: use a pointer to a slice (T[]*), and 
share that around. I don't see how I would get the current 
behavior if reallocation caused reassignment of all references 
(though admittedly I haven't thought too much about it).


Next up: does b, ending on the same element as a, refer to the 
whole length of a (i.e. should b's length be reassigned when a is 
reallocated?), or is it a slice only referencing the first three 
elements? Either choice is going to be unexpected in some cases.


All in all, there's many reasons to choose the behavior D has 
chosen. There are some drawbacks, but I feel it's the right 
choice.


--
  Simen


Re: How add class or struct member after construction?

2020-11-05 Thread Simen Kjærås via Digitalmars-d-learn

On Thursday, 5 November 2020 at 22:48:38 UTC, Marcone wrote:
How add class or struct member after construction? Is it 
possible in D? How?


This depends a lot on what you mean. The short answer is no - you 
cannot. However, given some limitations, it is possible. What 
sort of members do you need to add, and how will you be using 
them?


For instance, this works:

struct S {
import std.variant;
Variant[string] members;

Variant opDispatch(string name)() {
return members[name];
}
Variant opDispatch(string name, T)(T value) {
return members[name] = value;
}
}

unittest {
S s;
s.foo = 13;
assert(s.foo == 13);
}

--
  Simen


Re: this T / variadic template and interfaces

2020-10-26 Thread Simen Kjærås via Digitalmars-d-learn

On Monday, 26 October 2020 at 11:14:47 UTC, frame wrote:

Did not find this topic:

I have an interface and some wrapper classes that use it. The 
wrapper's methods should accept variadic arguments. The runtime 
should only work with the interface, trying casting to a 
wrapper is not an option, because it's a plugin design.


- defining a variadic template in wrapper does not work, 
because we are working with the interface only and compiler 
complains method is not callable with argument X


- defining a variadic template without body in interface causes 
linker errors, which makes sense somehow


- defining a variadic template with body in interface could 
work if the compiler would get the right "this" type but sadly, 
"this" refers to interface and also "this T" refers to 
interface too.


Is there any way to get this working? I know, I could use a 
known object to feed the arguments and use that instead - but I 
want to keep things simple as possible.


Templates can't be virtual, so even if they can be defined in an 
interface, you can't override them in a class that implements 
said interface - the implementation needs to be in the interface 
itself.


This makes sense if you consider that the user of the interface 
has no knowledge of the types that implement it, and vice versa: 
the implementing class has no idea which instantiations to make, 
and the user has no idea which implementing classes to create 
instantiations for. Templates require that the user have full 
knowledge of the templates to be instantiated.


There are some workarounds of sorts, but they depend heavily on 
what you're trying to achieve. Can you use an array of 
std.variant.Variant, for instance?


--
  Simen


Re: Call method of object variable

2020-10-16 Thread Simen Kjærås via Digitalmars-d-learn

On Friday, 16 October 2020 at 08:12:59 UTC, Andrey wrote:

Hi,
I have got:

struct Qaz
{
wstring read() {return null;}
wstring hear() {return "";} }

void main()
{
// ...
static if(some_condition) alias method = Qaz.hear;
else alias method = Qaz.read;

// ...
Qaz qaz;

qaz.method(); // ???
}


How to call alias "method" on object "qaz"?


https://dlang.org/spec/traits.html#child

The resulting code would be:

__traits(child, qaz, method)(/*arguments go here*/);

--
  Simen


Re: Why is "delete" unsafe?

2020-09-23 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 23 September 2020 at 04:15:51 UTC, mw wrote:
It's there because there _are_ times when it makes sense and 
is useful, but it's definitely not safe, so you have to be 
careful and know what you're doing.


What do you mean by saying "it's definitely not safe" here?

I mean: if I'm careful and know what I'm doing, e.g. remove all 
the reference to  any part of the `object` before call 
core.memory.GC.free(object), is there still any inherit 
"unsafe" side of `free` I should be aware of?


FYI: I just described my use case here:

https://forum.dlang.org/post/hzryuifoixwwywwif...@forum.dlang.org


If there are no lingering references, the function calling free() 
can safely be made @trusted.


--
  Simen


Re: Why private methods cant be virtual?

2020-09-22 Thread Simen Kjærås via Digitalmars-d-learn

On Tuesday, 22 September 2020 at 13:19:10 UTC, Daniel Kozak wrote:
So final private functions can be overriden? It seems not, but 
the sentence is definitely confusing if not just plain wrong.


Yeah. I've seen this called hiding, shadowing and overwriting 
earlier, but never overriding - that's always been reserved for 
the polymorphic kind.


I'd argue the documentation should use one of those other terms.


 And yes compiler probably could findout that method could be 
made
non-virtual but I am not sure how easy is this and how it would 
slow down

compilation times


Steve showed a few posts up one example that would make it 
basically impossible. Other language features make it even worse:


class A { private void fun() {} }
class B(string s) : A { mixin(s); }

--
  Simen


Re: Why is dtor called for lazy parameter?

2020-09-18 Thread Simen Kjærås via Digitalmars-d-learn
On Friday, 18 September 2020 at 14:14:31 UTC, Andrey Zherikov 
wrote:
It seems that dtor is called at exit from lazy delegate, not at 
exit form create():

==
create()
.do_something()
.do_lazy()
.do_something();
==
Output:
==
-> void test.main()
-> test.do_lazy(lazy S s)
-> test.create()
1 S test.S.this(int n)
<- test.create()
-> 1 test.do_something(S s)
<- 1 test.do_something(S s)
1 void test.S.~this()
===-1
<- test.do_lazy(lazy S s)
-> 1703096 test.do_something(S s)
<- 1703096 test.do_something(S s)
<- void test.main()
==

This doesn't even allow me to copy the value of 's' in 
do_lazy().


You're right, I missed a step: do_lazy() takes a S, not a 
scoped!S, so the conversion from scoped!S to S happens after 
create() has returned and before the value is used in do_lazy. 
This explains my confusion earlier.


D's lazy is essentially the same as a delegate or function, so 
you could* rewrite to this (writelns omitted for clarity):


S do_lazy(S function() s) {
return s();
}

void main() {
(() => cast(S)create()) // Here
.do_lazy()
.do_something();
}

On the marked line, the cast from scoped!S to S happens, the 
scoped!S goes out of scope and the destructor is called.


*There may be differences, but for this discussion these are not 
important.


--
  Simen


Re: Why is dtor called for lazy parameter?

2020-09-18 Thread Simen Kjærås via Digitalmars-d-learn
On Friday, 18 September 2020 at 12:32:49 UTC, Andrey Zherikov 
wrote:

==
The output is:
==
-> void test.main()
-> test.do_lazy(lazy S s)
-> test.create()
1 S test.S.this(int n)
<- test.create()
1 void test.S.~this()
===-1  (2)
<- test.do_lazy(lazy S s)
-> 1703096 test.do_something(S s)
<- 1703096 test.do_something(S s)
<- void test.main()
==

As you can see, dtor is called before writeln on (1) and s1.i 
is -1 (2)


Indeed. As we can see from the output, first do_lazy() is called 
from test.main, then create() is called (this happens inside 
do_lazy, as s is lazy). When create() returns, the scoped!S you 
created goes out of scope and is destroyed. scoped's destructor 
overwrites the memory with S.init, which is why s.i is -1 at that 
point. Then the memory is overwritten by subsequent function 
calls, as that stack space is now considered vacant. That's why 
the output changes from -1 to 1703096.


A bit interesting is the fact that <- test.create() is printed 
before ~this(). I expected the order to be opposite, but there 
may be sensible reasons why it's not.


scoped!S is only valid inside the scope its variable exists in, 
and when that scope is exited, it refers to random stack data. 
It's a lot like this code:


int* fun() {
int a;
int* p = 
return p;
}

Note that return  does not compile, with a warning about 
escaping a reference to a local variable. That's exactly the same 
thing that's happening with scoped!S, but since scoped is more 
complex, the compiler has a hard time keeping track of things, 
and code that in a perfect world would not compile, does. It may 
be that D's scope tracking functionality has become good enough 
to catch this error now, if the functions are properly marked. 
Even if this is the case, then they are obviously not properly 
marked. :p



Now, this begets the question: *when* should I use scoped!T?

Short answer: Basically never.

Longer answer:

1) When the lifetime of one object needs to be a strict subset of 
another. That is, the class instance you created only exists as 
long as the function create() is on the stack. When scoped!T is a 
member of another class or struct, it continues to live as long 
as that object exists. In most cases, you don't mind that it 
stays around for longer, and can let the GC handle the cleanup. 
If you really do care, you can use scoped!T, or explicitly 
destroy the object when you're done with it.


2) scoped!T may be used as a performance hack, letting you avoid 
the GC. If you have instrumented your code and found that this is 
the culprit, scoped!T might help. Even if GC is the problem, 
you'll still need #1 to be true.


There may be other cases, but I believe those are the main two 
reasons to use scoped!T.


--
  Simen


Re: Why is dtor called for lazy parameter?

2020-09-18 Thread Simen Kjærås via Digitalmars-d-learn
On Friday, 18 September 2020 at 10:43:47 UTC, Andrey Zherikov 
wrote:
Why is dtor called before returning from do_lazy function - see 
(1)? It seems cause uninitialized parameter in do_something 
call after it in (2)-(3).


As ikod mentions, it's because of scoped!S. As for why it does 
this, yeah, this is kinda egregious. The documentation[0] of 
scoped mentions this issue:


This facility is unsafe; it is the responsibility of the user 
to not escape a reference to the object outside the scope.


As the name implies, scoped!T limits the valid scope of a 
reference to the scope of the variable holding it. You're putting 
it on the stack, so the moment the variable goes off the stack 
(when do_lazy returns), the reference is destructed.


--
  Simen

[0]: https://dlang.org/library/std/typecons/scoped.html


Re: Type inference for constructors

2020-09-18 Thread Simen Kjærås via Digitalmars-d-learn
On Friday, 18 September 2020 at 05:43:56 UTC, data pulverizer 
wrote:
I’d like to know if constructors of classes and structs can 
have type inference. So far, I am using a separate function for 
this purpose, for example:


```
import std.stdio: writeln;

struct Pair(T, U)
{
  T first;
  U second;
  this(T first, U second)
  {
this.first = first;
this.second = second;
  }
}

Pair!(T, U) pair(T, U)(T first, U second)
{
  return Pair!(T, U)(first, second);
}

void main()
{
  auto mp = pair("Michael", 32);//standard function inference 
works
  //auto m0 = Pair("Michael", 32); //I’d like to be able to do 
this

  writeln("pair: ", mp);
}
```


That's issue 1997: https://issues.dlang.org/show_bug.cgi?id=1997

D's templates are turing complete, and there may be arbitrary 
amounts of logic obscuring the mapping between type template 
parameters and the specific argument types of the type's 
constructor, so the problem is intractable in the general case. 
E.g:


template Foo(T) {
static if (is(T == int)) {
struct Foo {
this(int i) {}
// int-specific code
}
} else {
struct Foo {
this(T t) {}
// generic code
}
}
}

The above example is a simple one, yet mapping from a constructor 
call to the correct template parameters is difficult.




[I] wondered what `this` in the code below does:

```
 auto ref opIndex(this X, D...)(auto ref D i) { return a[i]; }
```


That's a template this parameter 
(https://dlang.org/spec/template.html#template_this_parameter). 
It takes on the type of 'this' at the point of instantiation. 
That is:


struct S {
void fun(this T)() { pragma(msg, T); }
}

unittest {
S s;
const S sc;
immutable S si;
shared S ss;
s.fun();  // prints S
sc.fun(); // prints const(S)
si.fun(); // prints immutable(S)
ss.fun(); // prints shared(S)
}

This allows the return type to have the same constness as 'this', 
or for specific code to be executed when operating on e.g. a 
non-mutable instance, where lazy initialization couldn't be 
performed. In many cases, this is better served by using inout:


https://dlang.org/spec/function.html#inout-functions

--
  Simen


Re: another question on hidden mixin names

2020-09-17 Thread Simen Kjærås via Digitalmars-d-learn

On Thursday, 17 September 2020 at 21:05:59 UTC, 60rntogo wrote:

struct V
{
  int x;

  mixin assign!"+";
  // mixin assign!"-";
}

However, if I uncomment the second mixin, there is an error "v 
is not a scalar, it is a V". I guess I somehow need to merge 
these overloads, but I don't know how.


Usually, that would be:

struct V {
int x;

mixin assign!"+" a;
mixin assign!"-" b;
alias opOpAssign = a.opOpAssign;
alias opOpAssign = b.opOpAssign;
}

However, I can't seem to get that working. It seems to be an 
instance of this issue:

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

Note that explicitly calling the methods does work:

v.opOpAssign!"-"(v);
v.opOpAssign!"+"(v);


I don't know any good workarounds for this, you'll probably have 
to write a separate opOpAssign method for V that performs the 
forwarding to the mixed-in methods. This is, to put it very 
nicely, not an optimal solution.



btw, I'm somewhat surprised by your use of a template this 
parameter 
(https://dlang.org/spec/template.html#template_this_parameter). 
Generally this will work, but you're probably better off with


ref auto opOpAssign(string op)(typeof(this) rhs) if (op == 
op_)



--
  Simen


Re: enum and const or immutable ‘variable’ whose value is known at compile time

2020-09-17 Thread Simen Kjærås via Digitalmars-d-learn

On Thursday, 17 September 2020 at 10:56:28 UTC, Mike Parker wrote:

On Thursday, 17 September 2020 at 09:44:20 UTC, claptrap wrote:


Seriously how it's implemented is irrelevant.


And to be clear, my point wasn't about how it's implemented. My 
point was that:


enum { foo = 10; }

and

enum foo = 10;

Are effectively the same thing, whether it's implemented that 
way or not. So why on earth would a new keyword be necessary?


I could imagine some new users may think in

enum foo = someTemplate!();

someTemplate could evaluate to a list of values like a 'normal' 
enum. That's just conjecture, though. The one thing I dislike 
about enum like this is that we have another keyword that's able 
to handle manifest constants when tickled correctly, and which 
doesn't evoke the image of an enumerated list of values:


import std.meta : Alias;
alias foo = Alias!([1,2,3]);
alias bar = Alias!9;
alias baz = Alias!someFunc;

Some of the above may be doable without Alias!(), but not all. I 
don't know if you remember the discussions when bracketless enums 
were introduced back in 2007ish, but alias was the prime 
contender back then, and is slowly gaining the power that was 
requested at the time (the ability to alias values as above was 
added fairly recently).


To quote Bill Baxter from way back when
(https://forum.dlang.org/post/fjdc4c$2gft$1...@digitalmars.com):


> Why does:
> final int x = 3;
> make any more intuitive sense than:
> enum int x = 3;
> ?

There are these things called "words".  And they have 
"meanings"...

enum: (short for "enumeration", the noun form of "enumerate")
   "to specify one after another : list"
final:
   "not to be altered or undone "


To be clear: I don't mind 'enum' being used this way, but if I 
were to do things over again, I would have used 'alias'.


--
  Simen


Re: Neater "not version (...)" ?

2020-09-16 Thread Simen Kjærås via Digitalmars-d-learn
On Wednesday, 16 September 2020 at 19:04:24 UTC, Vladimirs 
Nordholm wrote:
On Wednesday, 16 September 2020 at 18:54:45 UTC, Jacob Carlborg 
wrote:

version (Windows)
enum windows = true;
else
enum windows = false;

static if (!windows)
{
// ... my code
}


Ah, I guess it boils down to this then. Doesn't really make it 
"neater", but thank you for the tip!


I wrote this helper a little while back:

struct Version {
template opDispatch(string name) {
mixin("version ("~name~") enum opDispatch = true; else 
enum opDispatch = false;");

}
}

static if (Version.Windows) pragma(msg, "Windows machine");
static if (Version.linux) pragma(msg, "Linux machine");

Note that it only works for global versions, and those defined in 
the same module as Version.


--
  Simen


Re: Why does compose from std.functional return a templated function

2020-09-16 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 16 September 2020 at 09:59:59 UTC, Jan Hönig wrote:
I have toyed with the compose template in std.functional and 
ran into some problems.

rikki_cattermole on discord helped me a lot to solve my problem.

However, what still remains (for me) to understand is why.

Source code for `compose`: 
https://github.com/dlang/phobos/blob/master/std/functional.d#L1161




`compose` pipes together given functions. And returns a 
TEMPLATED function.
Why does it return a templated function? At compile-time, 
compose definitly knows, what kinds of function it composes 
together. So with std.traits, it could put there a definitve 
type, depending on the given function(s).


I somewhat see, that inside compose itself, this probably 
solves some issues with casting (maybe).
However, the last composition, i.e. the one which is returned, 
does not need to be templated, since it is known, what 
parameter has the last function.


In my case, I failed to understand, that it returns a 
non-initialized template function, which lead into compile 
problems.


In general I can imagine that this leads to weird compile 
errors, which are hard to understand. (types, casting, etc.)



My main question is why? Is there something, which I am 
missing, that explains, why it is beneficial to return a 
templated function?


(maybe, because I might want to compose together templated 
non-initialized functions?)


It's perfectly possible to compose templated functions without 
wanting to specify the template parameters, and not allowing this 
would significantly hamper compose's usability.


The other complication is overloads. Here's a version of compose 
that generates the correct overloads:


template getOverloads(alias fn) {
static if (__traits(compiles, __traits(getOverloads, 
__traits(parent, fn), __traits(identifier, fn), true))) {
alias getOverloads = __traits(getOverloads, 
__traits(parent, fn), __traits(identifier, fn), true);

} else {
alias getOverloads = fn;
}
}

template compose(funs...) if (funs.length > 0) {
static foreach (overload; getOverloads!(funs[$-1])) {
static if (__traits(isTemplate, overload)) {
auto compose(Args...)(Args args) {
static if (funs.length == 1) {
return overload(args);
} else {
return funs[0](.compose!(funs[1..$])(args));
}
}
} else {
import std.traits : Parameters;
auto compose(Parameters!overload args) {
static if (funs.length == 1) {
return overload(args);
} else {
return funs[0](.compose!(funs[1..$])(args));
}
}
}
}
}

As you can see, this is *a lot* more complex than the version in 
std.functional. The benefit is you can take the address of it 
easily. Here's how you can do the same with 
std.functional.compose:


import std.functional : compose;
import std.meta : Instantiate;

unittest {
auto sun = !(compose!(fun, gun), int);
sun(3);
}

void fun(T)(T t) {
}

int gun(int t) {
return t;
}

I will argue the latter is an acceptable cost of avoiding the 
dense, bug-prone monstrosity of the former.


--
  Simen


Re: Get enum value name as string at compile time?

2020-09-14 Thread Simen Kjærås via Digitalmars-d-learn
On Monday, 14 September 2020 at 03:48:51 UTC, Steven 
Schveighoffer wrote:

Consider the enum:

enum Foo { a, b }

Foo.a.stringof => "a"
enum x = Foo.a;
x.stringof => "cast(Foo)0"

Is there another way I can take an enum value that's known at 
compile time (but not the actual identifier), and get the name 
of it? I know I can use a switch, or to!string. But I was 
hoping this was easy for the compiler to figure out some way 
without involving CTFE.


It is a bit weird that x.stringof doesn't simply return the name 
like Foo.a.stringof does. Anyways, this works:


template enumName(alias a) {
import std.meta : staticIndexOf, staticMap;

alias T = typeof(a);
enum getValue(string name) = __traits(getMember, T, name);
alias enumValues = staticMap!(getValue, __traits(allMembers, 
T));


enum enumName = __traits(allMembers, T)[staticIndexOf!(a, 
enumValues)];

}

enum Foo { a = 2, b = 19 }

enum x = Foo.a;
pragma(msg, enumName!x); // "a"

--
  Simen


Re: sending the address of a struct

2020-09-06 Thread Simen Kjærås via Digitalmars-d-learn

On Sunday, 6 September 2020 at 09:58:54 UTC, Johann Lermer wrote:

pointer. The error message says:

std.concurrency.MessageMismatch@std/concurrency.d(237): 
Unexpected message type: expected 'shared(Env*)', got 
'shared(test.Env)*'


The error message gives you all the information you need - notice 
the position of the asterisk inside the parens on one, outside on 
the other? The pointer itself is not shared, only the pointee - 
the data pointed to. This works:


auto e = receiveOnly!(shared(Env)*);

--
  Simen


Re: tupleof seems to break encapsulation

2020-09-04 Thread Simen Kjærås via Digitalmars-d-learn

On Friday, 4 September 2020 at 10:16:47 UTC, 60rntogo wrote:

Consider the following code.

foo.d
---
module foo;

struct Foo
{
  private int i;
}
---

main.d
---
void main()
{
  import std.stdio;
  import foo;

  auto x = Foo();
  writeln(x);
  // ++x.i;
  ++x.tupleof[0];
  writeln(x);
}
---

As expected, the commented line does not compile. If I 
uncomment it, I get the error "no property i for type foo.Foo". 
However, the rest of the code compiles just fine and outputs:

---
Foo(0)
Foo(1)
---

This appears to defeat the purpose of declaring i private. What 
am I missing?


It's a known issue: https://issues.dlang.org/show_bug.cgi?id=19326

There are some very good reasons to allow some access to private 
fields, though it should be more limited than is currently the 
case.


--
  Simen


Re: Tuple poilerplate code

2020-09-01 Thread Simen Kjærås via Digitalmars-d-learn

On Tuesday, 1 September 2020 at 02:08:54 UTC, JG wrote:
Is there anyway to remove the boilerplate code of dealing with 
tuples:


I find myself having to write things like this fairly often

auto someRandomName  = f(...); //where f returns a tuple with 
two parts

auto firstPart = someRandomName[0];
auto secondPart = someRandomName[1];


Is to possible to write something so that the above is 
essentially equivalent to:


assignTuple!(firstPart,secondPart) = f(...);

The closest I can produce is using a template mixin so that I 
would have to write:


mixin AssignTuple!(()=>f(...),"firstPart","secondPart");


When you know the types, this works:

import std.typecons : tuple;
import std.meta : AliasSeq;

int firstPart;
string secondPart;

AliasSeq!(firstPart, secondPart) = tuple(1, "foo");

assert(firstPart == 1);
assert(secondPart == "foo");

I know Timon Gehr worked on a DIP for improved tuples, which I 
think would include the syntax `auto (firstPart, secondPart) = 
tuple(1, "foo");`, but I don't know what's happened to that idea 
lately.



I also feel it's worth pointing out that Paul Backus' code looks 
elegant when used outside a map as well:


tuple(1, "foo").unpack!((i, s) {
writeln("i (", typeof(i).stringof, "): ", i,
  ", s (", typeof(s).stringof, "): ", s);
});

Will print:
i (int): 1, s (string): foo


--
  Simen


Re: Wrong selection of opEquals for objects.

2020-08-28 Thread Simen Kjærås via Digitalmars-d-learn
On Friday, 28 August 2020 at 13:35:43 UTC, Alexandru Ermicioi 
wrote:

On Friday, 28 August 2020 at 12:29:20 UTC, Simen Kjærås wrote:




Seems that these methods should be rooted out from Object, and 
placed in respective interfaces like:


-
interface Equatable(T) {
bool opEquals(T value);
}
-

Then it would be a lot more simple. People who want equality 
check, will implement interface with right type, for example 
Equatable!Object.


Yup, it's been proposed, but nothing's come of it yet. Here's 
Andrei's DIP on ProtoObject, which apparently is untouched for 
over two years now: 
https://github.com/andralex/DIPs/blob/ProtoObject/DIPs/DIP.md


The main problem with solving this issue is doing so will break 
all code that uses the current system. This is clearly suboptimal.


--
  Simen


Re: Wrong selection of opEquals for objects.

2020-08-28 Thread Simen Kjærås via Digitalmars-d-learn
On Friday, 28 August 2020 at 10:42:09 UTC, Alexandru Ermicioi 
wrote:
No that is not a solution at all, in template code that 
requires safety. You basically will have to sacrifice safety 
for rest of types, such as structs, unions & enums for the sake 
of objects being able to compare.


Yup. There's a reason I'm saying it's suboptimal. FWIW, you can 
limit the taint by using @trusted lambdas.


One of the reasons this hasn't been fixed is idiomatic D code 
very rarely uses classes, but that does not mean they're always 
the wrong tool.




Could we just template that opEquals in this manner:
---
bool opEquals(T : Object, X : Object)(T lhs, X rhs)
{
if (lhs is rhs) return true;

if (lhs is null || rhs is null) return false;

if (!lhs.opEquals(rhs)) return false;

if (typeid(lhs) is typeid(rhs) ||
!__ctfe && typeid(lhs).opEquals(typeid(rhs)))
{
return true;
}

return rhs.opEquals(lhs);
}
---

That would at least allow us to define an overload which is 
safe and would be picked up by new implementation.


I'm wondering why it wasn't done yet, are there any reasons for 
that?


The template solution may look like it solves every problem, but 
it really doesn't. Consider this code:


class A {
bool opEquals(A) { return false; }
}
class B : A {
bool opEquals(B) { return true; }
}

unittest {
B b1 = new B();
B b2 = new B();
A a1 = b1;
A a2 = b2;
assert(b1 == b2);
assert(a1 != a2); // WTF?
}

With the template solution, the function in B would be ignored 
when stored in a variable with static type A. This solution would 
sometimes do the right thing, other times it would silently do 
the wrong thing.





Also, why it is limited to just objects? It seems that this 
function enforces symmetry between two objects. What about rest 
of the possible types, such as structs, unions?


That's an issue. The spec clearly states 
(https://dlang.org/spec/operatoroverloading.html#equals):


2. [T]he expressions a.opEquals(b) and b.opEquals(a) are tried. 
If both resolve to the same opEquals function, then the 
expression is rewritten to be a.opEquals(b).
3. If one is a better match than the other, or one compiles and 
the other does not, the first is selected.

4. Otherwise, an error results.

This is clearly not the case:

struct S1 {
bool opEquals(S2 a) {
return true;
}
}
struct S2 {
bool opEquals(S1 a) {
return false;
}
}

unittest {
S1 a;
S2 b;
assert((a == b) == (b == a)); // Fails
}

I didn't find a bugzilla entry on this, but I'm pretty sure there 
is one.


As for why there's no global function like for classes, that's 
because there's no need - there is no disconnect between the 
static and dynamic types of non-class variables (or, if there is, 
it's explicitly programmed in, like in std.variant.Variant).


--
  Simen


Re: Wrong selection of opEquals for objects.

2020-08-28 Thread Simen Kjærås via Digitalmars-d-learn
On Friday, 28 August 2020 at 08:16:01 UTC, Alexandru Ermicioi 
wrote:

Hi everyone,

there is https://issues.dlang.org/show_bug.cgi?id=21180 bug, 
anyone knows how to avoid it?


Test case:
-
import std;

class Silly {
bool opEquals(const Silly silly) const @safe {
return silly is this;
}

alias opEquals = Object.opEquals;
}

bool comp(T)() @safe {
return new T() == new T();
}

void main()
{
comp!Silly.writeln;
comp!(const Silly).writeln;
comp!(immutable Silly).writeln;
}
-

It always tries to call Object.opEquals, when narrower overload 
should've been selected.


- Alex.


Essentially, this boils down to the issues described in 
https://issues.dlang.org/show_bug.cgi?id=1824, and a host of 
other bugzilla issues.


When you do a == b with a and b being class objects, it's lowered 
to object.opEquals(a, b)[0], which casts both a and b to Object 
before doing the comparison. So, you'll need to override 
Object.opEquals to have the right function called:


class Silly {
int field;
this(int f) {
field = f;
}
override bool opEquals(Object o) {
auto silly = cast(Silly)o;

// If cast returns null, it's not a Silly instance
if (!silly) return false;

// Compare Silly objects
return field == silly.field;
}
}

unittest {
Silly a = new Silly(1);
assert(a == new Silly(1));
assert(a != new Silly(2));
}

That takes care of choosing the correct overload, but as you may 
have noticed, there's another issue: your @safe function comp() 
can't call the @system function object.opEquals. Since 
object.opEquals operates on Object instances, not your specific 
subclass, it has to assume the worst, and is @system. There's no 
real good solution to that in the language as of now, and some of 
us have been pulling our hair for years because of it.


What you'll need to do is mark every function that does compare 
two class objects with == as @trusted or @system.


--
  Simen


[0]: 
https://github.com/dlang/druntime/blob/master/src/object.d#L166


Re: Can a call to pragma(msg, __FILE__, ...) be mixin templatized?

2020-08-18 Thread Simen Kjærås via Digitalmars-d-learn

On Tuesday, 18 August 2020 at 08:05:20 UTC, Per Nordlöw wrote:

On Tuesday, 18 August 2020 at 08:03:04 UTC, Per Nordlöw wrote:
Forgot to mention that I want to support variadic arguments to 
`ctLog` similar to what is done with


And these arguments should be of any template argument kind, 
not only a compile-time string.


I'm not a fan of string mixins (ask Adam how they're the scourge 
of good programming, a wart on D's behind, and so on :p), but I 
found no good way to do this without them:


string ctLog(Args...)(string file = __FILE__, size_t line = 
__LINE__) {

import std.conv : to;
string result = `pragma(msg, "`~file~`(", `~line.to!string~`, 
"): "`;

static foreach (e; Args) {
result ~= `, `~e.stringof;
}
return result~`);`;
}

mixin(ctLog!("This ", "is ", "module ", "scope."));
unittest {
mixin(ctLog!"function scope");
}
struct S {
mixin(ctLog!"Struct scope");
}

--
  Simen


Re: Can a call to pragma(msg, __FILE__, ...) be mixin templatized?

2020-08-17 Thread Simen Kjærås via Digitalmars-d-learn

On Monday, 17 August 2020 at 21:18:41 UTC, Per Nordlöw wrote:

I'm using

pragma(msg, __FILE__, "(", __LINE__, ",1): Debug: ", "A 
useful debug message");


to print compile-time information formatted as standard 
compiler diagnostics.


These are picked up by Emacs Flycheck and overlayed in the 
editor and listen in the *Flycheck errors* buffer. Very 
convenient. When I want to get the type of something at 
compile-time.


In order to not having to repeat oneself I'm now looking for a 
way to extract this into a `mixin template`. Is this possible 
somehow and still preserve the instantiation site values of 
`__FILE__` and `__LINE__`?


mixin template ctLog(string msg, string file = __FILE__, size_t 
line = __LINE__) {

pragma(msg, file, "(", line, "): ", msg);
}

mixin ctLog!"Module scope";
unittest {
mixin ctLog!"function scope";
}
struct S {
mixin ctLog!"Struct scope";
}

This works for me.

--
  Simen


Re: Template: get function name

2020-08-17 Thread Simen Kjærås via Digitalmars-d-learn

On Monday, 17 August 2020 at 08:07:32 UTC, novice3 wrote:

Hello.
I have wrapping Windows API functions, wich return 0 on success 
and erroro code on failure.


I copy wenforce template as:
```
private T denforce(T, S)(T value, lazy S msg = null, string 
file = __FILE__, size_t line = __LINE__)

{
  import core.sys.windows.winerror: NO_ERROR;
  import std.conv: to;
  if (value != NO_ERROR)
throw new WindowsException(value, to!string(msg), file, 
line);

  return value;
}
```

and use it:
```
DhcpEnumServers(0, null, servers, null, 
null).denforce("DhcpEnumServers");



Then windows api - extern (Windows)DhcpEnumServers - return 
error, then Windows exception throwed with name of failed api 
"DhcpEnumServers".


Can we change template to avoid api name dublicate?
Can denforce template obtain "DhcpEnumServers" function name to 
format message "DhcpEnumServers api failed"?


Thanks.


Take the function as an alias parameter and wrap the entire call:

auto denforce(alias fn, string file = __FILE__, size_t line = 
__LINE__, Args...)(Args args) {

import core.sys.windows.winerror: NO_ERROR;
auto value = fn(args);
if (value != NO_ERROR) {
throw new WindowsException(value, __traits(identifier, 
fn)~" api call failed.", file, line);

}
return value;
}

unittest {
denforce!DhcpEnumServers(0, null, servers, null, null);
}

For bonus points, you could also get the error message for the 
returned error code:


string convertErrorCode(uint code) {
import core.sys.windows.winbase : FormatMessage, LoadLibrary, 
FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_IGNORE_INSERTS, 
FORMAT_MESSAGE_FROM_HMODULE;

wchar[512] buf;

auto written = FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | 
FORMAT_MESSAGE_IGNORE_INSERTS,

null,
code,
0,
buf.ptr, buf.length,
null);

if (!written) {
auto inst = LoadLibrary("Ntdsbmsg.dll");
if (inst) {
written = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | 
FORMAT_MESSAGE_IGNORE_INSERTS,

inst,
code,
0,
buf.ptr, buf.length,
null);
}
}
if (written) {
import std.conv : to;
return buf.ptr.to!string;
} else {
import std.format : format;
return format("An unknown error occured: %x", code);
}
}

unittest {
import core.sys.windows.winerror : ERROR_INVALID_FUNCTION;

import std.stdio;
writeln(convertErrorCode(ERROR_INVALID_FUNCTION));
writeln(convertErrorCode(1234567891));
}

--
  Simen


Re: Cannot call @system funciton (stdout)

2020-08-16 Thread Simen Kjærås via Digitalmars-d-learn

On Saturday, 15 August 2020 at 23:59:36 UTC, Joel wrote:
../../JMiscLib/source/jmisc/base.d(176,2): Error: @safe 
function jmisc.base.upDateStatus!string.upDateStatus cannot 
call @system function 
std.stdio.makeGlobal!"core.stdc.stdio.stdout".makeGlobal
/Library/D/dmd/src/phobos/std/stdio.d(4837,20):
std.stdio.makeGlobal!"core.stdc.stdio.stdout".makeGlobal is 
declared here


I got around it by avoiding 'stdout'.


First, what's wrong with using writeln and friends instead of 
directly mucking about with stdout? :p


stdout is __gshared, so it's available on any thread at any time. 
That's not @safe, so it's @system.


If you know you're not using stdout from multiple threads, or 
don't care (it might be perfectly safe even though it's possible 
to misuse), you can use this code:


@property File trustedStdout() @trusted
{
return stdout;
}

That's a @trusted wrapper that you can call from @safe code. It's 
not actually safe though, as multiple threads could be using 
trustedStdout at the same time. In many use cases, this is 
unlikely to matter, but it's wroth keeping in mind.


--
  Simen


Re: can't access an alias created inside an if statement

2020-08-05 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 5 August 2020 at 09:32:58 UTC, Flade wrote:
Thanks! You see it should work but the thing is. I'm using it 
inside a function. I'm checking for one of the function's 
parameter (if parameter == false) and it says that "the 
variable `parameter` cannot be read at compile time. Do you 
know if there is a way to fix this?


As the error message says, the value must be known at compile 
time. Most likely, you can simply pass it as a template parameter:


void fun(bool parameter)(int arg1, string arg2) {
static if (parameter) {
}
}

void main() {
fun!true(1, "foo");
fun!false(19, "bar");
}

--
  Simen


Re: can't access an alias created inside an if statement

2020-08-05 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 5 August 2020 at 09:05:36 UTC, Flade wrote:
I have used an if-else statement to create an alias to avoid 
code duplication but it doesn't let me access it outside the if 
statement. Is there a way to solve this?


You're probably looking for static if:

static if (useAlias) {
alias myAlias = getAlias!();
}

myAlias foo = getFoo();


What happens is a regular if statement introduces a scope, so 
anything declared inside it is unavailable outside. static if 
does not introduce a new scope, and so its contents can be 
accessed.


static if only works with compile-time constant conditions, but 
aliases are also compile-time constructs, so this should not pose 
a problem.


--
  Simen


Re: miscellaneous array questions...

2020-07-21 Thread Simen Kjærås via Digitalmars-d-learn
On Tuesday, 21 July 2020 at 13:42:15 UTC, Steven Schveighoffer 
wrote:

On 7/21/20 8:34 AM, Adam D. Ruppe wrote:

The others aren't wrong about stack size limits playing some 
role, but the primary reason is that it is a weird hack for 
@safe, believe it or not.

...
I don't recall exactly when this was discussed but it came up 
in the earlier days of @safe, I'm pretty sure it worked before 
then.


I think this was discussed, but was not the reason for the 
limitation. The limitation exists even in D1, which is before 
@safe: https://digitalmars.com/d/1.0/arrays.html#static-arrays


I have stressed before that any access of a pointer to a large 
object in @safe code should also check that the base of the 
object is not within the null page (this is not currently 
done). This is the only way to ensure safety.


It seems the limitation was introduced in DMD 0.123, in May 2005:
https://forum.dlang.org/post/d61jpa$1m0l$1...@digitaldaemon.com
Walter gives some justification in the post immediately following:

1) Gigantic static arrays are often either the result of a typo 
or are a

newbie mistake.
2) Such require a lot of memory for the compiler to handle. 
Before the OS
officially runs out of memory, it goes to greater and greater 
lengths to
scavenge memory for the compiler, often bringing the computer 
to its knees

in desperation.
3) D needs to be a portable language, and by capping the array 
size a

program is more likely to be portable.
4) Giant arrays are reflected in a corresponding giant size for 
the exe

file.
5) There simply isn't a need I can think of for such arrays. 
There shouldn't

be a problem with allocating them dynamically.


I admit I thought it was an old optlink limitation, but it seems 
it's basically arbitrary.


--
  Simen


Re: What's the point of static arrays ?

2020-07-10 Thread Simen Kjærås via Digitalmars-d-learn

On Friday, 10 July 2020 at 10:13:23 UTC, wjoe wrote:
However stack memory needs to be allocated at program start. I 
don't see a huge benefit in allocation speed vs. heap 
pre-allocation, or is there?
I mean 1 allocation vs 2 isn't going to noticeably improve 
overall performance.


You seem to still be thinking of static arrays as the same kind 
of "thing" as a dynamic array. They're (usually) more like ints 
or structs than containers: they're generally small, they're 
often parts of other structures or classes, and they're fairly 
often the element type of a larger dynamic array. For instance, a 
bitmap image could be a byte[4][][], with dynamic dimensions 
3840x2160. If instead of byte[4] we used byte[], not only would 
things grind to a halt immediately, we'd also be using massively 
more memory.


When you're using a static array on the stack, it's usually just 
because it's more convenient to say `int[16] buffer;` than `auto 
buffer = new int[16];`. The fact it may be faster is mostly a 
side benefit. Also, even if you did preallocate such a buffer, 
there's the overhead of remembering how to get to it, the work of 
setting it up, probably a function call on use, etc. The 
alternative is terser, built-in, more obvious to maintainers, 
pretty unlikely to overflow the stack, and very unlikely to be 
slower. Allocating a multi-MiB static array on the stack is a 
sign that you're using your screwdriver as a hammer, and there 
are probably better ways to do what you're trying to do.




a[]

What happens here exactly ?


It creates a dynamic array that points to the data in the static 
array. It's just shorthand for a[0..$]:


unittest {
int[4] a = [1,2,3,4];

auto b = a[];
assert(b.length == 4);
assert(b.ptr == [0]);

auto c = a[0..$];
assert(b is c);
}

--
  Simen


Re: What's the point of static arrays ?

2020-07-09 Thread Simen Kjærås via Digitalmars-d-learn

On Thursday, 9 July 2020 at 12:12:06 UTC, wjoe wrote:
I'm not considering supposed performance benefits/penalties 
because these need to be profiled.


Considering the many downsides why would I ever want to choose 
a static over a dynamic array ?


Simply put: static arrays are not dynamic arrays, and if you try 
to use one as the other you're going to be disappointed.


Usually, you use static arrays when you interface with something 
else that does it - generally a file format or a C library. For 
the most part you're right, you should probably use a dynamic 
array instead.


Now, as for your points:


- Can neither grow nor shrink them
- Can't append elements
- Can't remove elements


These are the same as the first point.



- Can't slice them
- Can't range them


Sure you can:

unittest {
import std.stdio;
import std.algorithm;
int[10] a = [1,2,3,4,5,6,7,8,9,10];

// Note I'm slicing the static array to use in range 
algorithms:

writeln(a[].map!(b => b+2));

// Slicing works:
auto b = a[3..6];
b[] = 7;
writeln(a);
}



- Assignment copies the whole array, as in int[5] a; auto b = a;


This is often a factor in choosing a static array. It's not 
better or worse, just different. And sometimes it's different in 
exactly the way you need.




- Size is limited by stack
- Stack overflow issues


So allocate your static array on the heap if this is a problem?



Some of the cons could be considered a feature.
Also GC but it's possible to make a dynamic array 
implementation which avoids the GC.


Basically none of the drawbacks you refer to are actual 
drawbacks, but instead part of what makes static arrays useful. 
Static arrays are not a poor man's dynamic arrays, they're a 
different beast, doing different things.


--
  Simen


Re: Progress printing with threads?

2020-07-01 Thread Simen Kjærås via Digitalmars-d-learn

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


Suppose the program is processing a very big file and is 
iterating the file's bytes using a for loop. The processing 
takes several minutes and I want a progress percentage be 
printed every 2 seconds in this manner:


Progress: 0.40%
Progress: 3.20%
Progress: 5.73%

Is it a good idea to std.concurrency.spawn a new thread and 
pass to it

cast(float)i * 100 / fileSize
somehow? If not, what's a better way to do this?

This example code shows my situation:

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

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

Thanks in advance.


If doing the update in the same thread that does the processing 
is somehow not an option, this works for me:


import std.concurrency;
import std.stdio;
import core.thread;
import core.time;

void main() {
ulong filesize = 1234;
ulong i = 0;
Tid progress = spawn((shared const(ulong)* p, ulong f){
while (!receiveTimeout(2000.msecs, (int i){ })) {
writeln(*p, "/", f, ": ", *p*100.0/f, "%");
}
}, cast(shared), filesize);
for (; i < filesize; ++i) {
// Process
}
progress.send(0); // Stop
}

There's a cast to shared there which may be suboptimal, but since 
the progress thread is only reading it, I would say it's ok.


--
  Simen


Re: Generating struct members from c structs

2020-07-01 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 1 July 2020 at 07:26:44 UTC, Anthony wrote:
When doing interop with a c library, is there a way to 
automatically generate the fields that are needed for a struct?

[snip]

Is there an easier way though?


Dstep is probably what you're looking for: 
https://github.com/jacob-carlborg/dstep


It eats C header files and creates appropriate D files from them.

--
  Simen


Re: scope guard question

2020-07-01 Thread Simen Kjærås via Digitalmars-d-learn
On Tuesday, 30 June 2020 at 12:18:14 UTC, Steven Schveighoffer 
wrote:
I can see where it would be confusing, and it could probably 
contain an example and clarification.


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


Re: How to implement Canceleable spawn() from parent

2020-06-30 Thread Simen Kjærås via Digitalmars-d-learn

On Tuesday, 30 June 2020 at 13:44:38 UTC, aberba wrote:

On Tuesday, 30 June 2020 at 12:48:32 UTC, Simen Kjærås wrote:

On Tuesday, 30 June 2020 at 08:15:54 UTC, aberba wrote:

On Tuesday, 30 June 2020 at 00:33:41 UTC, Ali Çehreli wrote:

On 6/29/20 4:34 PM, aberba wrote:

> So with this, without the Thread.sleep() to block main from
exiting, the
> spawned thread  will terminate immediately.

You can call core.thread.thread_joinAll at the end of main.
So I tried that initially but my (){ writeln(...) } wasn't 
printing anything in console. Could that be related to stdout 
buffering? The program kept running though.






So I guess the error is elsewhere, but I'm not sure where and 
how.


Yeah, you're right. I changed receiveTimeout() to receive() to 
try something and forgot to change it back.


Jeez, I hate myself.

Thanks.


So how can I now hide the core.thread.thread_joinAll so the 
library user doesn't have to type it themselves in main() ? I 
don't see how that can be done.


__gshared Tid mainTid;
static this() {
if (mainTid.tupleof[0] is null) {
mainTid = thisTid;
}
}
static ~this() {
if (thisTid == mainTid) {
thread_joinAll();
}
}

The above code does the trick.

So, what does it do? __gshared means 'this variable is accessible 
to all threads'. static this() runs upon creation of any thread 
including the main thread. Since the main thread will run first*, 
it gets to store its Tid in mainTid, and every other thread will 
see a populated mainTid and leave it alone. In the module 
destructor, which runs after main(), we call thread_joinAll() iff 
we're the main thread.


Now, why should you not do this? Well first, instead of getting a 
tidy crash you get a process that doesn't end. Second, there's 
the race conditions described below. Third, there's the principle 
of least astonishment. D programmers expect that when main() 
returns, the program will exit shortly(ish), while this zombie 
could continue running indefinitely.


--
  Simen


*I'm pretty sure this is possibly wrong, if a module constructor 
spawns a new thread. There's also a possible race condition where 
newly spawned modules may conceivably not see a properly 
initialized mainTid.


Re: How to implement Canceleable spawn() from parent

2020-06-30 Thread Simen Kjærås via Digitalmars-d-learn

On Tuesday, 30 June 2020 at 08:15:54 UTC, aberba wrote:

On Tuesday, 30 June 2020 at 00:33:41 UTC, Ali Çehreli wrote:

On 6/29/20 4:34 PM, aberba wrote:

> So with this, without the Thread.sleep() to block main from
exiting, the
> spawned thread  will terminate immediately.

You can call core.thread.thread_joinAll at the end of main.
So I tried that initially but my (){ writeln(...) } wasn't 
printing anything in console. Could that be related to stdout 
buffering? The program kept running though.


Seems weird. This works great on my machine:


import core.time : Duration, msecs;
import core.thread : Thread, thread_joinAll;
import std.concurrency : spawn, Tid, send, receiveTimeout;
import std.stdio : writeln;

private struct IntervalStop {}

Tid setInterval(Duration dur, void function() fn) {
return spawn((Duration d, void function() f){
while (!receiveTimeout(d, (IntervalStop s){})) {
f();
}
}, dur, fn);
}

void stopInterval(Tid tid) {
tid.send(IntervalStop());
}

void main() {
auto a = setInterval(1000.msecs, (){ writeln("Hello from 
spawned thread A"); });

// Stop it before it happens
stopInterval(a);
Thread.sleep(2000.msecs);

auto b = setInterval(1000.msecs, (){ writeln("Hello from 
spawned thread B"); });

// Let this one run a little
Thread.sleep(2500.msecs);
stopInterval(b);

auto c = setInterval(1000.msecs, (){ writeln("Hello from 
spawned thread C"); });
// Sending the wrong message doesn't make it happen or stop 
prematurely

c.send("Stop this at once!");
Thread.sleep(2500.msecs);
stopInterval(c);

thread_joinAll();
}

So I guess the error is elsewhere, but I'm not sure where and how.

--
  Simen


Re: Unused template arguments; what type to use?

2020-06-26 Thread Simen Kjærås via Digitalmars-d-learn

On Friday, 26 June 2020 at 13:21:25 UTC, drathier wrote:
How can I tell the compiler that I will never create a value of 
type X, while still being able to write code that uses it? 
Using void as a template parameter is where I started, but I 
still need to be able to declare variables inside this 
unreachable function, like `T foo;` even when `T == void`. Can 
I get any closer to what I want than an empty struct?


Depends on what you care about, I guess. A final abstract class 
has been my go-to on a few occasions. I'd argue the empty struct 
is better in most cases, and a forward-declared struct with no 
implementation might work in some cases.


--
  Simen


Re: Flagging special conditions on return from a function call

2020-06-23 Thread Simen Kjærås via Digitalmars-d-learn

On Tuesday, 23 June 2020 at 04:01:45 UTC, Denis wrote:
(1) Assign an unused value for the flag (e.g. -1 when the 
function returns an int), and return the combined value/flag.


This happens in some Phobos algorithms, and might be the most 
common on this list.




(2) Return a tuple with the value and the flag
(3) Return a struct or tuple with named value and flag members


Would certainly work, but I don't think it's common in D.


(4) Set the function return value normally, and put the flag in 
an "out" variable passed as an argument to the function
(5) Return the flag, and put the value in an "out" variable 
passed to the function (i.e. the reverse of #4)


Both of these happen. I don't know which is more common. In C# 
these are probably the most common way (except for exceptions) to 
signal these cases.



(6) Use two separate functions, one that returns the value, and 
another that can be called afterwards to check the flag (like 
eof(), for example)




(7) Use a side effect and set a designated global variable


Global variables are frowned upon, so probably not this. :p


One thing I feel is missing here (perhaps because 
std.variant.Algebraic is egregious):


(8) Return a Maybe!T or Algebraic!(T, ErrorCode)

It's what I personally would prefer, but I have only rarely seen 
it in D code. Given a properly written Maybe, this could enforce 
proper handling of the error case, either by throwing on trying 
to get at Maybe!T.getValue when it's holding None, or by 
presenting an interface that only compiles when both cases are 
covered, like fun().match((T t) => t, () => Error()).


--
  Simen


Re: Parallel array append using std.parallelism?

2020-06-19 Thread Simen Kjærås via Digitalmars-d-learn

On Thursday, 18 June 2020 at 14:43:54 UTC, H. S. Teoh wrote:
I have an array of input data that I'm looping over, and, based 
on some condition, generate new items that are appended onto a 
target array (which may already contain data). Since the 
creation of new items is quite expensive, I'm thinking to 
parallelize it with parallel foreach.


To avoid data races, my thought is for each generated item to 
be appended to thread-specific temporary arrays, that after the 
parallel foreach get sequentially appended to the target array. 
Something like this:


Item[] targetArray = ...; // already contains data
Item[][nThreads] tmp;
foreach (elem; input.parallel) {
if (condition(elem)) {
auto output = expensiveComputation(elem);
tmp[threadId] ~= output;
}
}
foreach (a; tmp)
targetArray ~= a;

Is there an easy way to achieve this with std.parallelism?  I 
looked over the API but there doesn't seem to be any obvious 
way for a task to know which thread it's running in, in order 
to know which tmp array it should append to.  If possible I'd 
like to avoid having to manually assign tasks to threads.


There's an example of exactly this in std.parallelism: 
https://dlang.org/phobos/std_parallelism.html#.TaskPool.workerIndex


In short:

Item[] targetArray = ...; // already contains data
// Get thread count from taskPool
Item[][] tmp = new Item[][taskPool.size+1];
foreach (elem; input.parallel) {
if (condition(elem)) {
auto output = expensiveComputation(elem);
// Use workerIndex as index
tmp[taskPool.workerIndex] ~= output;
}
}
foreach (a; tmp)
targetArray ~= a;

--
  Simen


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

2020-06-17 Thread Simen Kjærås via Digitalmars-d-learn

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


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


The heuristic I use is 'do I need polymorphism?' If no, it's a 
struct. Another thing that may be worth considering is reference 
semantics. The latter is easy to do with a struct, while 
polymorphism is generally a class-only thing (but check out 
Tardy, which Atila Neves recently posted in the Announce group).


I would say I basically never use classes in D - pointers and 
arrays give me all the reference semantics I need, and 
polymorphism I almost never need.


--
  Simen


Re: `this` template params for struct not expressing constness.

2020-06-08 Thread Simen Kjærås via Digitalmars-d-learn

On Monday, 8 June 2020 at 09:08:40 UTC, adnan338 wrote:

On Monday, 8 June 2020 at 08:10:19 UTC, Simen Kjærås wrote:

On Monday, 8 June 2020 at 07:35:12 UTC, adnan338 wrote:

Self* searchTree(this Self)(auto in ref T item) const {
if ( is null)
return null;
if (this.item == item)
return 
return (this.item < item) ?
this.right.searchTree(item) :
this.right.searchTree(item);
}


This method is const, which means 'this' is const, while Self 
is not. What you're looking for here is inout 
(https://dlang.org/spec/function.html#inout-functions):


auto searchTree()(auto in ref T item) inout {
if ( is null)
return null;
if (this.item == item)
return 
return (this.item < item) ?
this.right.searchTree(item) :
this.right.searchTree(item);
}

--
  Simen


Thank you. Few followup questions, if you don't mind.

1. What does that blank template parameter mean?


Just forces the function to be a template. The only reason for 
this is it's required for auto ref to work, which you may or may 
not need on that function.



2. Since `inout` acts as a wildcard for 
immutable/const/non-const qualifiers, what should I do to have 
the compiler ensure that my method does not mutate a non-const 
tree inside the body?


Inside inout functions, `this` is treated as const - any attempt 
to modify it should give a compile error. Since D const is 
transitive, anything reachable from `this` is also treated as 
const.  If you're able to mutate a non-const tree inside the 
body, there's a bug in the compiler.



--
  Simen


Re: `this` template params for struct not expressing constness.

2020-06-08 Thread Simen Kjærås via Digitalmars-d-learn

On Monday, 8 June 2020 at 07:35:12 UTC, adnan338 wrote:

Self* searchTree(this Self)(auto in ref T item) const {
if ( is null)
return null;
if (this.item == item)
return 
return (this.item < item) ?
this.right.searchTree(item) :
this.right.searchTree(item);
}


This method is const, which means 'this' is const, while Self is 
not. What you're looking for here is inout 
(https://dlang.org/spec/function.html#inout-functions):


auto searchTree()(auto in ref T item) inout {
if ( is null)
return null;
if (this.item == item)
return 
return (this.item < item) ?
this.right.searchTree(item) :
this.right.searchTree(item);
}

--
  Simen


Re: how to append (ref) int[] to int[][]?

2020-06-08 Thread Simen Kjærås via Digitalmars-d-learn

On Monday, 8 June 2020 at 06:13:36 UTC, mw wrote:

Hi,

I have this program:

import std.stdio;

void f(ref int[] arr) {
arr ~= 3;
}

void main() {
int[][] arrs;
int[] arr;
foreach (i; 0 .. 3) {
arr = new int[0];
arrs ~= arr; //(a) [[], [], []]
f(arr);
// arrs ~= arr; //(b) [[3], [3], [3]]
}

writeln(arrs);
}


This program will print out [[], [], []].

If I comment out (a), and use (b), it will print out [[3], [3], 
[3]]


So based on this behavior, looks like "~=" will append a copy 
of `arr`; but what I really want in (a) is append `ref arr` and 
output [[3], [3], [3]], i.e. the real `arr` be appended instead 
of its copy.


I have to say this semantics surprised me.

I tried to change arrs' decl to:

(ref (int[]))[] arrs;  // the intended semantics I want

But I got compiler error out: "found ( when expecting function 
literal following ref".


1) I'm wondering how to achieve what I want? and
2) why "~=" here will append a copy rather than the real `arr` 
itself to arrs?


Arrays (technically, slices) in D are essentially this struct:

struct Array(T) {
T* ptr;
size_t length;
// operator overloads
}

So when you have int[][], each element of the outer array is an 
Array!int. These, as simple structs, are copied about, so that 
changing one does not change another.


The simple solution here is to call f not on arr, but on 
arrs[$-1] (the last element of arrs). If that is not possible you 
will need arrs to be an int[]*[].


--
  Simen


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

2020-06-04 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 3 June 2020 at 15:25:51 UTC, Paul Backus wrote:

On Wednesday, 3 June 2020 at 13:24:17 UTC, Basile B. wrote:
This is because the template parameter must be resolved to a 
valid symbol or type.

This version other version bypass the problem:

---
enum Exists(string s) = is(typeof(mixin(s)));

void main()
{
static if (!Exists!"foo")
int foo;
foo = 42;
}
---


Fails if the symbol in question is the name of a type.

struct Foo {}
enum Exists(string s) = is(typeof(mixin(s)));
static assert(Exists!"Foo"); // false

What you actually want is something like this:

enum Exists(string s) = __traits(compiles, { mixin("alias _ 
= ", s, ";"); });


And they both fail if the thing you refer to isn't available in 
the scope where Exists is defined. I believe this covers most 
cases, but there may very well be corner cases I haven't 
considered:


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

// Handles values:
int global;
unittest {
int local;
{
int outOfScope;
}
static assert(mixin("local".exists));
static assert(mixin("global".exists));
static assert(!mixin("outOfScope".exists));
}

// And types:
struct Global {}
unittest {
struct Local {}
{
struct OutOfScope;
}
static assert(mixin("Global".exists));
static assert(mixin("Local".exists));
static assert(!mixin("OutOfScope".exists));
}

// But not expressions:
static assert(!mixin("1+2".exists));
// Correctly fails for missing declarations:
static assert(!mixin("nowhere".exists));

Like Stefan said though, we're quite a bit off from the original 
request - the above certainly shouldn't be faster than drathier's 
original code. The only advantage I see is that it might read a 
little clearer.


--
  Simen


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

2020-06-03 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 3 June 2020 at 09:39:34 UTC, Basile B. wrote:

You can use this template:

  enum Exists(alias T) = is(typeof(T));

I don't know if there's a faster way bu this technic is used, 
notatbly in phobos, to workaroud issues of double declaration 
in `static foreach`


enum Exists(alias T) = is(typeof(T));
static assert(!Exists!bar); // undefined identifier bar

--
  Simen


Re: Unable to access a variable declared inside an if statement (Error: is shadowing variable)

2020-05-27 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 27 May 2020 at 11:03:51 UTC, BoQsc wrote:
I'm lacking knowledge on how to achieve what I want and getting 
an error.
What is the correct way to do what I tried to achieve in this 
code?
Everything was intuitive until I started to add notice variable 
to the writeln. Rdmd says  variable `notice` is shadowing 
variable.



if (driveLetter.exists){
auto directory = "/Backup";
if ((driveLetter ~ directory).exists){
auto notice = "Backup directory exists.";

}
writeln(driveLetter, notice);
}


Variables only live in a specified scope, starting from where 
they are declared, and ending when they reach the '}' indicating 
the end of said scope.


In you case, 'notice' only lives inside the if ((driveLetter ~ 
directory).exists) scope, and doesn't exist outside. In order to 
fix this, you will need to declare it outside:


if (driveLetter.exists) {
auto directory = "/Backup";
auto notice = "Backup directory does not exist.";
if ((driveLetter ~ directory).exists) {
notice = "Backup directory exists.";
}
writeln(driveLetter, notice);
}

This also makes it clearer what value 'notice' will have when the 
backup directory doesn't exist - in your case you haven't 
assigned it any value in that case.


--
  Simen


Re: opEquals @safe is ignored

2020-05-24 Thread Simen Kjærås via Digitalmars-d-learn

On Sunday, 24 May 2020 at 08:57:28 UTC, Luis wrote:

dmd ignores @trusted or @safe on opEquals, throwing this error :

onlineapp.d(27): Error: @safe function 
onlineapp.__unittest_L24_C7 cannot call @system function 
object.opEquals


An override @system or @trusted function can't be @safe, or I 
it a bug ?


Also, how will this be affected by DIP1028 ?


Looking at the output, it's actually druntime's opEquals that 
can't be called. That's the global function that ensure opEquals 
is called on both sides of the comparison, and it's not @safe. 
This makes classes even worse to use in D than, and I'm not sure 
how to properly handle this. If we make it @trusted, suddenly I 
can call @system opEquals from @safe functions without issue.


Root cause is, classes in D all inherit from Object, which has 
some defaults that aren't always what you want. It seems DIP1028 
will make your code automatically compile, along with this:


class C {
override bool opEquals(Object o) @system {
*cast(int*)123456 = 3;
return true;
}
}

@safe void mySafeFunction() {
assert(new C() == new C());
}

--
  Simen


Re: Assignment of tuples

2020-05-20 Thread Simen Kjærås via Digitalmars-d-learn
On Wednesday, 20 May 2020 at 13:51:05 UTC, Steven Schveighoffer 
wrote:

Please file an issue.


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

--
  Simen


Re: Bug?

2020-05-11 Thread Simen Kjærås via Digitalmars-d-learn

On Monday, 11 May 2020 at 12:44:45 UTC, Jack Applegame wrote:

On Monday, 11 May 2020 at 12:30:22 UTC, Adam D. Ruppe wrote:
UFCS is only defined to work with global scope functions. A 
restricted import (module : symbol, symbols) puts things in 
local scope so ufcs doesn't apply.


But in this case the error should be displayed for lines 4 and 
5, not 11.

Line 11 contains a call to a member function, not UFCS.

In addition, if you add the parentheses, then it works:
assert(rng.front() == '1');


You're right, and it absolutely seems the call on lines 4 and 5 
work correctly. Instead, the compiler is confused by the presence 
of two different overloads for front in Range!T, and doesn't 
attempt to call the one it can call. We get the exact same 
behavior here:


struct S {
int gun()(int i) { return 0; }
alias fun = gun;
int fun() { return 1; }
}

static assert(S().fun == 1);

Filed here: https://issues.dlang.org/show_bug.cgi?id=20821

--
  Simen


Re: What could this be?

2020-05-11 Thread Simen Kjærås via Digitalmars-d-learn

On Monday, 11 May 2020 at 11:20:51 UTC, Joel wrote:
I'm gotten stuck with this error - "..is not visible from 
module.."


Without some code it's hard to say exactly, but this generally 
means you're referencing a private symbol in a different module:


module foo;
private struct S {}

module bar;
import foo;
foo.S s; // foo.S is not visible from module bar

--
  Simen


Re: How does a free list work?

2020-05-09 Thread Simen Kjærås via Digitalmars-d-learn

On Saturday, 9 May 2020 at 19:54:44 UTC, Pavel Shkadzko wrote:
I have been reading about memory management in D on 
https://wiki.dlang.org/Memory_Management and found an example 
of a free list (pattern?): "Free lists are a great way to 
accelerate access to a frequently allocated and discarded 
type.".


Here is the example of free list:
---
class Foo
{
static Foo freelist; // start of free list
Foo next; // for use by FooFreeList

static Foo allocate()
{
Foo f;

if (freelist)
{
f = freelist;
freelist = f.next;
}
else
f = new Foo();
return f;
}

static void deallocate(Foo f)
{
f.next = freelist;
freelist = f;
}
}
---

Do I understand correctly that by switching between static and 
non-static Foo we keep the object from being garbage collected 
by the GC? So in a situation when I need to create an object 
and then discard it, I can implement this pattern to use memory 
more efficiently.


Also, it's a little strange that since both f and freelist are 
null we are basically doing null = null in first if condition.


The GC keeps a list of roots - that is, objects that are known to 
be active and should not be collected. The static freelist is one 
of those - since it's static it should of course never be 
collected.


From these roots, the GC scans all referenced objects 
recursively, and finally releases all memory that has not been 
scanned (and that thus have no path of pointers leading from a 
root to that memory).


Since any call to new will check if memory is available, and 
potentially trigger a GC collection, it can be expensive, so if 
you can avoid allocating and deallocating objects a lot, it's an 
easy optimization.


To more clearly show this, here's some code that prints what it 
does:


import std.stdio : writeln;

class Foo {
static Foo freelist;

Foo next;
string name;
this(string name) {
this.name = name;
}
~this() {
writeln("GC collecting ", name);
}

static Foo allocate(string name) {
if (freelist) {
auto f = freelist;
freelist = f.next;
writeln("Fetching ", f.name, " from freelist, 
changing name to ", name);

f.name = name;
return f;
}
writeln("Nothing in freelist, allocating new ", name);
return new Foo(name);
}

static void deallocate(Foo f) {
writeln("Adding ", f.name, " to freelist, freelist.next 
points to ",

freelist ? freelist.name : "(null)");
f.next = freelist;
freelist = f;
}
}

unittest {
Foo a = Foo.allocate("A");
Foo b = Foo.allocate("B");
Foo c = Foo.allocate("C");
Foo.deallocate(a);
Foo.deallocate(b);
a = null;
b = null;
c = null;

import core.memory;
GC.collect();
// For some reason I need to call this twice for C to be 
collected?

GC.collect();

Foo d = Foo.allocate("D");
Foo e = Foo.allocate("E");
Foo f = Foo.allocate("F");
}

The above code creates this output:

Nothing in freelist, allocating new A
Nothing in freelist, allocating new B
Nothing in freelist, allocating new C
Adding A to freelist, freelist.next points to (null)
Adding B to freelist, freelist.next points to A
GC collecting C
Fetching B from freelist, changing name to D
Fetching A from freelist, changing name to E
Nothing in freelist, allocating new F
1 unittests passed
GC collecting E
GC collecting D
GC collecting F


Here's what it does in more words:

For the first call to allocate(), the freelist is null, and a new 
Foo is created in the 'else' path, before being returned. Nothing 
is assigned to freelist or next.


The second and third call does the exact same thing, since 
nothing has been assigned to the freelist.


We then deallocate a, which assigns it to the freelist. Next we 
deallocate b, which sets b's 'next' field to point at a, and sets 
freelist to point at b. We then set a, b, and c to null, so those 
references will no longer keep the Foos alive.


Then we call GC.collect, which finds that the Foo previously 
stored in b is now in freelist, and thus will be kept. The Foo 
that was in a is referenced by freelist.next, and will also live. 
The foo in c, however, is no longer referenced anywhere, and will 
be collected.


This shows the main point of the freelist - to ensure the objects 
aren't collected by the GC - but what happens afterwards?


When we allocate d, freelist points at the Foo that used to be 
stored in b, so it is returned from allocate(), and the freelist 
is changed to point to the Foo that used to be in a.


Allocating e there's still something in freelist, so it is 
returned. At this point the freelist is empty, and allocating f 
creates a new Foo, just like when we allocated a, b, and c.


--
  

Re: XMM Intrinsics

2020-05-08 Thread Simen Kjærås via Digitalmars-d-learn

On Friday, 8 May 2020 at 13:09:49 UTC, kinke wrote:

On Friday, 8 May 2020 at 12:49:00 UTC, Simen Kjærås wrote:
How would I go about calling _mm_* functions in D in a way 
that is portable between D compilers?


You would use core.simd:


Nope one wouldn't, because that horrible interface isn't 
supported by LDC, and I guess GDC neither.


The intel-intrinsics dub package aims to provide a 
compiler-independent layer: 
https://code.dlang.org/packages/intel-intrinsics


TIL, thanks! :)

--
  Simen


Re: XMM Intrinsics

2020-05-08 Thread Simen Kjærås via Digitalmars-d-learn

On Friday, 8 May 2020 at 12:38:51 UTC, Marcio Martins wrote:

Hi,

I am building a CRC32C implementation using SSE for D, because 
I couldn't find any readily available :[


However, I am unable to find any documentation regarding which 
SSE instructions are available and how I could use them in D. I 
can see core.simd can't seem to make any use of it.


How would I go about calling _mm_* functions in D in a way that 
is portable between D compilers?


You would use core.simd:

https://dlang.org/library/core/simd.html


Sadly, the supported instructions are not documented on that 
page, and you'll need to look at the source to get at them:


https://github.com/dlang/druntime/blob/master/src/core/simd.d#L85-L384

(I'll file a bug on this)


There's a bit more info on D SIMD instructions here:

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

--
  Siomen


Re: Is there a way to benchmark/profile portably?

2020-05-07 Thread Simen Kjærås via Digitalmars-d-learn

On Thursday, 7 May 2020 at 10:21:07 UTC, Dukc wrote:
Is there some way to measure the performance of a function so 
that the results will be same in different computers (all x86, 
but otherwise different processors)? I'm thinking of making a 
test suite that could find performance regressions 
automatically.


I figured out Bochs[1] could be used for that, but it seems an 
overkill for me to install a whole virtual operating system 
just to benchmark functions. Does anybody know more lightweight 
way?


[1] http://bochs.sourceforge.net/


If I understand correctly, you want to measure how many cycles 
pass, rather than clock time?


If so, it seems perf can do that: 
https://perf.wiki.kernel.org/index.php/Tutorial


--
  Simen


Re: variant visit not pure?

2020-05-07 Thread Simen Kjærås via Digitalmars-d-learn

On Thursday, 7 May 2020 at 09:22:28 UTC, learner wrote:

Good morning,

Is there a reason why std.variant.visit is not inferring pure?

```
void test() pure {
Algebraic!(int, string) alg;
visit!( (string) => 0, (int) => 0)(alg);
}

Error: pure function test cannot call impure function 
test.visit!(VariantN!(16LU, int, string)).visit

```


std.variant.Algebraic is essentially a std.variant.Variant in 
different clothes. Variant is very flexible, and this comes at a 
cost (and isn't used in Algebraic, meaning you pay for things you 
don't use). Like Dukc said, you might be better off with 
Taggedalgebraic or SumType 
(https://code.dlang.org/packages/sumtype).



Variant uses runtime type information to hold *any* type. Since 
Algebraic specifically only holds a few types, all the framework 
that's in place for Variant is wasted on Algebraic, and makes it 
less useful and less performant.


--
  Simen


Re: Bug?

2020-05-04 Thread Simen Kjærås via Digitalmars-d-learn

On Tuesday, 5 May 2020 at 04:02:06 UTC, RazvanN wrote:

truct K
{
~this() nothrow {}
}

void main()
{
static class C
{
this(K, int) {}
}

static int foo(bool flag)
{
if (flag)
throw new Exception("hello");
return 1;
}

try
{
new C(K(), foo(true));
}
catch(Exception)
{
}
}

Result:

object.Exception@test.d(18): hello

If the destructor of K is not marked nothrow the code does not 
throw an exception. Is this a bug or am I missing something?


Surely the above code, which silently discards the exception, 
does not print "hello"?


Regardless, I ran your code with writeln inside the catch(), and 
without the try-catch entirely, with and without nothrow on K's 
destructor. I am unable to replicate the issue on my computer 
with DMD 2.091.0, as well as on run.dlang.io. Is something 
missing in your code here?


--
  Simen


Re: Aliasing current function template instance

2020-05-01 Thread Simen Kjærås via Digitalmars-d-learn

On Friday, 1 May 2020 at 20:28:58 UTC, Jean-Louis Leroy wrote:
Is it possible, inside a function template, to create an alias 
to the instantiated function? IOW the equivalent of 
__FUNCTION__, but yielding an alias?


The closest I came is:

  import std.string;
  import std.traits;

  void foo(T)(lazy T)
  {
mixin(
  "alias thisFunction = ",
  __FUNCTION__[0..__FUNCTION__.lastIndexOf('.')],
  ";");
pragma(msg, Parameters!thisFunction);
  }

  void main()
  {
foo(0);
foo("");
  }

  dmd -c aliasthisfunction.d
  (lazy int)
  (lazy string)

...but (unsurprisingly) this fails in presence of overloads. 
I.e. if I throw in:


  void foo(T)(int, T);

...then I get:

  aliasthisfunction.d(6): Error: template 
`aliasthisfunction.foo` matches more than one template 
declaration:

  aliasthisfunction.d(4): `foo(T)(lazy T)`
  and
  aliasthisfunction.d(20): `foo(T)(int, T)`
  ...

Something I have overlooked? Any ideas?


This should work:

alias context(alias a) = __traits(parent, a);

void fun() {
alias ctx = context!({})();
}

{} becomes a lambda inside fun(), so it's parent is fun(). The 
same could be done by introducing a symbol explicitly, but that 
pollutes the namespace. This template works inside functions, 
methods, lambdas, modules, structs, classes and interfaces.


--
  Simen


Re: Can't recreate a range?

2020-04-30 Thread Simen Kjærås via Digitalmars-d-learn

On Thursday, 30 April 2020 at 13:23:25 UTC, Paul Backus wrote:

On Thursday, 30 April 2020 at 13:04:47 UTC, Casey wrote:

Here's a minimal code example that duplicates the issue:

import std.array, std.range, std.stdio, std.traits, std.string;

auto readStream(Range)(auto ref Range r) if 
(isInputRange!(Unqual!Range))

{
struct StreamRange(Range)
{
alias R = Unqual!Range;
R _input;

auto buff = appender!string;


Using a default value like this means that it will be shared 
among all instances of the struct. Instead, you should set 
`buff = appender!string` in the constructor, so that each 
struct will have its own appender.


Yup, that's the one. No need to assign it at all, in fact - the 
line can be replaced with


Appender!string buff;

And things just work.

--
  Simen


Re: Can't recreate a range?

2020-04-29 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 29 April 2020 at 20:43:20 UTC, Casey wrote:

void popFront()
{
}


I mean, it might be you messed up in posting this, but having an 
empty popFront and expecting it to do something is a tad 
optimistic.


Apart from that, it seems like the code should do what you want 
it to. What's the value of count when the code asserts? I'm 
afeared we'll need some code that actually compiles and shows off 
the issue to give any more answers.


--
  Simen


Re: Can’t use UFCS to create InputRange?

2020-04-29 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 29 April 2020 at 09:16:58 UTC, user1234 wrote:
The static checker doesn't see your free funcs because to do so 
it would have to import the whole module. (is it possible to do 
that ? no idea.)


Of course it's possible! :) We can find the context of R (in this 
case, the module) with __traits(parent), and import that:


mixin("import "~__traits(parent, R).stringof["module 
".length..$]~";");


However, doing that in isInputRange doesn't help much. First, all 
other range functions would have to do it, and second, just 
importing into function scope doesn't enable UFCS lookup.



Also your signature for the primitives are quite unusual (i.e 
not idiomatic). Usually they dont take param. Usually we pass a 
type that contains the member funcs matching to IsIntputRange.


You can see a good counterexample to this in 
https://dlang.org/library/std/range/primitives/pop_front.html, 
which defines popFront for regular arrays. However, that is the 
one and only counterexample I know of.


Of course, nothing stops us from defining our own front, popFront 
and friends that combine the two approaches above:



template front(R) {
auto front(R r) {
return __traits(getMember, __traits(parent, R), 
"front")(r);

}
}
template popFront(R) {
auto popFront(R r) {
return __traits(getMember, __traits(parent, R), 
"popFront")(r);

}
}
template empty(R) {
auto empty(R r) {
return __traits(getMember, __traits(parent, R), 
"empty")(r);

}
}

We could conceivably add these to std.range.primitives (probably 
adding some constraints first), and suddenly UFCS ranges are 
possible! (I am as of yet not convinced that we should, though)


--
  Simen


Re: Can’t use UFCS to create InputRange?

2020-04-29 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 29 April 2020 at 08:34:53 UTC, Ogi wrote:

struct R {}
int front(R r) { return 42; }
void popFront(R r) {}
bool empty(R r) { return false; }

void main() {
import std.range.primitives : isInputRange;
static assert(isInputRange!R);
}


Error: static assert:  `isInputRange!(R)` is false


What’s going on here?



The template IsInputRange is in the std.range.primitives module, 
and thus can't see the front, popFront and empty definitions in 
your module.


--
  Simen


Re: How convert String to Hex?

2020-04-18 Thread Simen Kjærås via Digitalmars-d-learn

On Saturday, 18 April 2020 at 15:47:38 UTC, Marcone wrote:

How convert String to Hex?

Example:

string text = "Hello World"; // Converted to Hex = 
48656c6c6f20576f726c64


import std.format : format;

string hex = format("%(%2x%)", "Hello World");

import std.stdio : writeln;
writeln(hex);

A bit of explanation: %(  %) is a range formatting specifier, and 
basically means "format each element of the range with the format 
specifier between these two symbols". In other words, it's the 
equivalent of "Hello World".map!(c => format("%2x", c)).joiner.


--
  Simen


Re: Extracting user defined attributes on function parameters

2020-04-18 Thread Simen Kjærås via Digitalmars-d-learn

On Saturday, 18 April 2020 at 09:19:48 UTC, Simen Kjærås wrote:
On Wednesday, Friday, 17 Apr 2020 17:45:47 UTC, H. S. Teoh 
wrote:


I wonder if the ultimate cause of the above case is ultimately 
caused by
the change to import semantics that hid private symbols from 
outside the
module. Perhaps something, somewhere, is triggering an illegal 
access of
a private symbol, which percolates up the call/instantiation 
stack and

causing what appears to be a strange compiler discrepancy.


Not unlikely. Importing the module defining S in the module 
defining ParameterDefaults does indeed make things compile. 
Hiding S by making it private makes the error return.


It's not about private. Or even if it is, there's other issues. 
Proof:


struct A {
struct S {}
void f(@S int = 3);
pragma(msg, Issue20744!f);
}

template Issue20744(func...) {
static if (is(typeof(func[0]) PT == __parameters)) {
alias Issue20744 = (PT args) {};
}
}

--
  Simen


Re: Extracting user defined attributes on function parameters

2020-04-18 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, Friday, 17 Apr 2020 17:45:47 UTC, H. S. Teoh wrote:

I wonder if the ultimate cause of the above case is ultimately 
caused by
the change to import semantics that hid private symbols from 
outside the
module. Perhaps something, somewhere, is triggering an illegal 
access of
a private symbol, which percolates up the call/instantiation 
stack and

causing what appears to be a strange compiler discrepancy.


Not unlikely. Importing the module defining S in the module 
defining ParameterDefaults does indeed make things compile. 
Hiding S by making it private makes the error return.


(for whatever reason your message isn't visible in the web 
interface)


--
  Simen


Re: Extracting user defined attributes on function parameters

2020-04-17 Thread Simen Kjærås via Digitalmars-d-learn

On Friday, 17 April 2020 at 16:54:42 UTC, Adam D. Ruppe wrote:

This part seems fine...


pragma(msg, ParameterDefaults!f.stringof);


It is this, specifically, that causes the problem. Replace it 
with:


void main() {
import std.stdio;
writeln(ParameterDefaults!f.stringof);
}

and it is fine.

So pragma(msg) is doing something really weird, the bug doesn't 
appear to be in Phobos per se, I think it is the compiler doing 
the wrong thing, it seems to me it works inside a function 
scope but not at module scope..


It's even more fascinating - the issue doesn't occur if 
ParameterDefaults is defined in the same module that it's used 
in, and it works if there's a type with the same name as the UDA. 
Reducing the code as much as I can, I get this:


struct S {}

void f(@S int = 3);

pragma(msg, ParameterDefaults!f.stringof);

template ParameterDefaults(func...) {
import std.traits : FunctionTypeOf;
static if (is(FunctionTypeOf!(func[0]) PT == __parameters)) {
enum ParameterDefaults = (PT[0..1] args) @trusted {
return *&(args[0]);
}();
}
}


The above code works, and prints "3". If you move 
ParameterDefaults to a different module, something like this:


-

import bar;

struct S {}

void f(@S int = 3);

pragma(msg, ParameterDefaults!f.stringof);

-

module bar;

template ParameterDefaults(func...) {
static if (is(typeof(func[0]) PT == __parameters)) {
enum ParameterDefaults = (PT[0..1] args) @trusted {
return *&(args[0]);
}();
}
}
-

Then you get an error message about 'undefined identifier S'. Add 
some kind of S to bar, and you get an error message about S not 
being readable at compile-time or things just work if it is 
readable. It seems the UDA is being looked up in the wrong 
context.


--
  Simen


Re: Checked!({short, ushort, byte, ubyte}, Throw): compilation fails

2020-04-17 Thread Simen Kjærås via Digitalmars-d-learn

On Friday, 17 April 2020 at 08:59:19 UTC, kdevel wrote:

On Friday, 17 April 2020 at 04:29:06 UTC, Meta wrote:
Unlike C/C++, char is not a numeric type in D; It's a UTF-8 
code point:


Thanks, it's a code /unit/. main reads now:

void main ()
{
   bar!ubyte;
   bar!byte;
   bar!ushort;
   bar!short;
   bar!uint;
   bar!int;
   bar!ulong;
   bar!long;
}

and dmd complains:



The problem is, short/short gives an int answer:

unittest {
import std.experimental.checkedint;
Checked!(short, Throw) a;
pragma(msg, typeof(a/a));
}

So, in your code you get this situation:

unittest {
import std.experimental.checkedint;
Checked!(int, Throw) a;
Checked!(short, Throw) b = a;
}

And assigning from an int to a short may discard data, so it's 
statically disallowed by Checked. This is a deliberate design 
choice, and the appropriate way to handle it is with a cast:


unittest {
import std.experimental.checkedint;
Checked!(int, Throw) a = 65535;
Checked!(short, Throw) b = cast(short)a;
}

The above code will throw when casting (before the assignment), 
because 65535 can't fit in a short.


You also get a deprecation message, about an integral promotion 
not being performed. I believe the result is correct and the 
warning can be ignored.


--
  Simen


Re: Find the heir.

2020-03-29 Thread Simen Kjærås via Digitalmars-d-learn

On Sunday, 29 March 2020 at 14:04:53 UTC, TodNaz wrote:

Hello!

class A
{
   ...
}

class B : A
{
   ...
}

class C : A
{
   ...
}

A example1;
B example2 = new B(...);
A = example2;
auto heir = A.whoheir(); ///


The question in this code is: is it possible to track the class 
inheritor? Or is it beyond D?

Sorry if the question is fool ...


The question is a bit unclear - what is whoheir expected to 
return? This is one way that may or may not fulfill your 
requirements:


module foo;
class A {
string whoheir() {
return typeid(this).name;
}
}
class B : A {}
class C : A {}

unittest {
A a = new B();
assert(a.whoheir == "foo.B");
a = new C();
assert(a.whoheir == "foo.C");
}

--
  Simen


Re: Get symbols (and/or UDAs) of subclass from superclass

2020-03-15 Thread Simen Kjærås via Digitalmars-d-learn

On Sunday, 15 March 2020 at 20:18:03 UTC, James Blachly wrote:
I would like to programmatically retrieve members of a subclass 
to create a self-documenting interface. I am afraid that my 
approach is not possible due to need for compile time __traits 
/ std.traits, and runtime typeinfo. My proposed approach is as 
follows:


class Base
{
string whatever;

string toString()
{
// loop over __traits(allMembers, typeof(this)) or 
getSymbolsByUDA, etc.

}
}

/// There may be a dozen Derived classes
class Derived1 : Base
{
@Config("a name", "a description")
float probability;
}
class Derived2 : Base
{
@Config("another", "more description")
int replicates;
}
...


There's no built-in way to do this - toString() doesn't know what 
derived classes exist, and more could be added from other modules 
and even dynamically loaded libraries. Now, there are ways to do 
something somewhat like it. I would suggest creating an abstract 
method in the base class, that derived class would have to 
override, and use a template this argument to get the correct 
type for __traits(allMembers) to operate on:


class Base {
override string toString() {
return toStringImpl();
}
abstract string toStringImpl();
string toStringBase(this That)() {
// foreach (e; __traits(allMembers, That) {...}
}
}

class Derived : Base {
override string toStringImpl() {
return this.toStringBase();
}
}

Since toStringImpl will always call toStringBase, this could 
perhaps better be modeled with a template mixin:


mixin template DerivedToString() {
override string toStringImpl() {
return this.toStringBase();
}
}

class Derived2 : Base {
mixin DerivedToString!();
}

This way, you can have all the logic of toString in the base 
class, and the only thing a subclass will have to include is one 
line for the mixin. In addition, since toStringImpl is abstract, 
the implementer of a subclass will get a compile-time error if he 
or she forgets to do either the mixin or override toStringImpl 
themselves.


--
  Simen


Re: A set type implemented as an AA wrapper

2020-03-12 Thread Simen Kjærås via Digitalmars-d-learn

On Thursday, 12 March 2020 at 08:51:24 UTC, mark wrote:
I use sets a lot and since I believe that D's rbtree is O(lg n) 
for add/remove/in and that D's AA is O(1) for these, I want to 
implement a set in terms of an AA.


Below is the code I've got so far. It allows for add and 
remove. However, it has three problems (that I know of):


XXX: I need to use an if on the struct to restrict T to be a 
type that supports toHash and opEquals (i.e., to be a valid AA 
key)


I'd suggest simply testing if an AA with that key type is valid:

struct AAset(T) if (is(int[T]))


YYY: The range() method is clearly not good D style but I don't 
know how to support foreach (item; aaset) ...


As Ferhat points out, you could use opApply for this. There's 
also the option of implenting the range primitives front, 
popFront() and empty. However, the easiest solution is the one 
you've already chosen, combined with alias this:


struct AAset(T) if (is(int[T])) {
// stuffs...
auto range() { return set.byKey; }
alias range this;
}



ZZZ: I can't figure out how to support the in operator.


'in' for AAs returns a pointer to the value it finds, or null if 
no item is found. This pointer does not implicitly convert to 
bool when returned from a function, so you need to compare it to 
null:


bool opBinaryRight(string op)(T lhs) {
static if (op == "in") return (lhs in set) != null;
else static assert(0, "operator " ~ op ~ " not 
supported");

}

I would also suggest using a template specialization instead of 
static if and static assert:


bool opBinaryRight(string op : "in")(T lhs) {
return (lhs in set) != null;
}

--
  Simen


Re: Aliases to mutable thread-local data not allowed [testable source code]

2020-03-11 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 11 March 2020 at 12:43:28 UTC, mark wrote:

On Wednesday, 11 March 2020 at 12:22:21 UTC, Simen Kjærås wrote:

On Wednesday, 11 March 2020 at 09:29:54 UTC, mark wrote:

[snip]
Fascinating. It works just fine when compiling for 32-bit 
targets with DMD on Windows, but not for 64-bit targets, nor 
when compiling with LDC. Apparently, this difference is due to 
DMD supporting 80-bit reals, and thus giving a different size 
to Variant (VariantN!20 on DMD on Windows, VariantN!16 or 
VariantN!32 elsewhere). There's a bug in VariantN that then 
causes the compilation to fail 
(https://issues.dlang.org/show_bug.cgi?id=20666).


The issue at hand then, is that Deb is too big until that 
issue if fixed. The simple solution to this is to allocate Deb 
on the heap with new and pass pointers instead of instances 
directly. Since you are already calling .dup whenever you pass 
a Deb somewhere, you can simply modify .dup to return a Deb* 
and the receive function to receive a Deb*, and I think you 
should be good to go.


I did that and it compiles & runs, but no Debs get added to the 
collection.
See https://github.com/mark-summerfield/d-debtest-experiment -- 
the 'mto' version is the one with your fixes.


Yeah, I forgot we cast to immutable to be able to send, so 
receive has to receive immutable(Deb)*, after which you can call 
deb.dup to get a mutable copy:


receive(
(immutable(Deb)* deb) { debForName[deb.name] = deb.dup; },
(DoneMessage m) { jobs--; }
);


--
  Simen


Re: Aliases to mutable thread-local data not allowed [testable source code]

2020-03-11 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 11 March 2020 at 09:29:54 UTC, mark wrote:

Hi Simen,

I think you must have done something else but didn't mention to 
get it to compile. I did the exact changes you said and it 
wouldn't compile. Here's what I get with changes mentioned 
below (with new full source):


Fascinating. It works just fine when compiling for 32-bit targets 
with DMD on Windows, but not for 64-bit targets, nor when 
compiling with LDC. Apparently, this difference is due to DMD 
supporting 80-bit reals, and thus giving a different size to 
Variant (VariantN!20 on DMD on Windows, VariantN!16 or 
VariantN!32 elsewhere). There's a bug in VariantN that then 
causes the compilation to fail 
(https://issues.dlang.org/show_bug.cgi?id=20666).


The issue at hand then, is that Deb is too big until that issue 
if fixed. The simple solution to this is to allocate Deb on the 
heap with new and pass pointers instead of instances directly. 
Since you are already calling .dup whenever you pass a Deb 
somewhere, you can simply modify .dup to return a Deb* and the 
receive function to receive a Deb*, and I think you should be 
good to go.


--
  Simen


Re: Aliases to mutable thread-local data not allowed [testable source code]

2020-03-11 Thread Simen Kjærås via Digitalmars-d-learn

On Tuesday, 10 March 2020 at 20:03:21 UTC, mark wrote:

I've managed to make a cut-down version that's < 170 LOC.
It needs to be run on Debian or a Debian-based Linux (e.g., 
Ubuntu).


Hopefully this will help someone understand and be able to help!


This took some time figuring out. Turns out, 
std.concurrency.spawn won't take a delegate as its callable 
argument. There are sensible reasons for this - delegates have a 
context that is not guaranteed to be immutable, so allowing 
delegate callables could lead to mutable aliasing. I've filed an 
issue to improve documentation and error messages: 
https://issues.dlang.org/show_bug.cgi?id=20665


However, knowing that some things are impossible do not 
necessarily help us figure out what we can do to fix the problem, 
and the good news is, the problems can be fixed. Since the 
problem is we're giving a delegate where the API expects a 
function, we can simply turn it into a function. In the code 
you've given, that means making readPackageFile and 
readPackageLine static. This make spawn() run as it should.


In addition, there's a problem with this line in receive():

(DoneMessage) { jobs--; }

That looks sensible, but since DoneMessage doesn't have a name, 
it is parsed as a templated function taking one argument of 
unspecified type and called DoneMessage. For some reason, 
templates passed as function arguments show up in compiler output 
as 'void', giving this weird error message:


template std.concurrency.receive cannot deduce function from 
argument types !()(void delegate(Deb deb) pure nothrow @safe, 
void)


The solution here is to simply give DoneMessage a name:

(DoneMessage d) { jobs--; }

With those changes, things at least compile. Now it's up to you 
to ensure the semantics are correct. :)


One last thing: you're passing parentTid around, and that's not 
actually necessary - std.concurrency.ownerTid does the exact same 
thing, and is available even if not explicitly passed anywhere.


--
  Simen


Re: Aliases to mutable thread-local data not allowed

2020-03-10 Thread Simen Kjærås via Digitalmars-d-learn

On Tuesday, 10 March 2020 at 08:13:19 UTC, mark wrote:

I have this struct:

struct Deb {
string name;
...
Unit[string] tags; // set of tags

Deb dup() const {
Deb deb;
deb.name = name;
...
foreach (key; tags.byKey)
deb.tags[key] = unit;
return deb;
}
}



void readPackageFile(Tid parentTid, string filename) { // (some 
code elided)

try {
Deb deb;
auto file = File(filename);
foreach(lino, line; file.byLine.enumerate(1))
readPackageLine(parentTid, filename, lino, line, 
deb);
// readPackageLine also calls send with same code 
as AAA below

if (deb.valid)
send(parentTid, deb.dup); // AAA




/home/mark/opt/ldc2-1.20.0-linux-x86_64/bin/../import/std/concurrency.d(625,5): Error: 
static assert:  "Aliases to mutable thread-local data not allowed."

Is there any nice solution to this? Surely it is a common 
pattern to read multiple files and create lots of data items to 
be merged into a collection?


As the error message hints at, the problem is Deb may hold 
references to data that is shared with other objects on the 
thread from which it originates. Since you know this is not the 
case, even if the compiler can't prove it, you can safely cast 
your Deb to immutable:


if (deb.valid)
send(parentTid, cast(immutable)deb.dup);

In fact, even the .dup is unnecessary here, since no data is 
shared with other objects, so you can simply write 
send(parentTid, cast(immutable)deb);. (Note on this point: since 
you have not included all your code, it could be other parts 
create shared mutable state, in which case .dup is necessary, and 
if badly written may not be sufficient.


--
  Simen


Re: @property with opCall

2020-03-09 Thread Simen Kjærås via Digitalmars-d-learn

On Monday, 9 March 2020 at 09:25:31 UTC, Calvin P wrote:

Is this a bugs ?

==
struct A {
ref auto opCall(string tmp) scope return {
return this;
}
}

struct B {
A _a;

@property ref auto a() scope return {
return _a;
}
}

extern(C) int main(){
A a;
a("a")("b");
B b;
b.a("a")("b");  // Error: function test_opCall.B.a() is 
not callable using argument types (string)

return 0;
}
==


I has to use  b.a()("a")("b") to avoid the compiler error. I 
think it should work to avoid the unnecessary ()


Should I submit a bugs ?


As written on 
https://dlang.org/spec/function.html#property-functions:


WARNING: The definition and usefulness of property functions is 
being reviewed, and the implementation is currently incomplete. 
Using property functions is not recommended until the 
definition is more certain and implementation more mature.


So no, I don't think it's necessary to file a bug - we're aware 
they're somewhat wonky, and until a resolution has been agreed 
on, I don't think filing bugs on what's undecided behavior is 
worth it.


--
  Simen


Re: Idiomatic way to express errors without resorting to exceptions

2020-03-09 Thread Simen Kjærås via Digitalmars-d-learn

On Saturday, 7 March 2020 at 15:44:38 UTC, Arine wrote:
The case when there isn't a value should be handled explicitly, 
not implicitly. Propogating a None value

isn't useful


Except when it is useful, and shouldn't be handled explicitly. I 
have code in D, C and C++ that looks like this:


ReturnValue result = someInitialValue;
auto foo = getFoo();
if (!foo) return result;
auto bar = foo.fun();
if (!bar) return result;
return bar.gun();

In C#, this would be:

return getFoo()?.fun().gun() ?? someInitialValue;

And with implicit handling in Optional!T, it looks like this:

return getFoo().oc.fun().gun().or(someInitialValue);

Clearly the latter two are more readable, and I'm not gonna care 
that it's a little slower in the 99% of cases where speed is not 
important.


--
  Simen


Re: What does assigning void mean?

2020-03-05 Thread Simen Kjærås via Digitalmars-d-learn

On Thursday, 5 March 2020 at 08:35:52 UTC, drug wrote:

On 3/5/20 10:47 AM, mark wrote:
In Adam Ruppe's D Cookbook there're these lines in a ref 
counting example:


RefCountedObject o = void; // What does this mean/do?
o.data = new Implementation();
o.data.refcount = 1;

I don't understand the first line; could someone explain 
please?



In D all vars are initialized by default. If you use assigning 
void then the var won't be initialized.


To expand a bit on this: You probably don't want to initialize 
things with = void - it can lead to hard-to-track bugs and 
unexpected behavior. The reasons it's there is almost entirely as 
an optimization - if you know the variable will be initialized 
elsewhere void initialization ensure things won't be initialized 
twice when once is enough, and this can be faster.


The other use case is when for whatever reason there is no valid 
default value, but you still want an instance. Probably in order 
to fill it with data from somewhere else. This would apply e.g. 
to structs with @disabled parameterless constructors whose 
contents you are reading from disk.


In short, when you know you need to void initialize something, 
that's when you're ready to use it. Kinda like goto.


--
  Simen


Re: Call method if declared only

2020-02-28 Thread Simen Kjærås via Digitalmars-d-learn

On Friday, 28 February 2020 at 10:33:11 UTC, Виталий Фадеев wrote:

Thanks all !
I happy !
Check this one:
void On( T, M )( T o, M message )
{

[snip]

void main()
{
auto a = new A();
a.Send( a, WM_KEYUP );
a.Send( a, WM_KEYDOWN );
}


That does mostly work, but fails for this code:

void main()
{
Base a = new A();
a.send( a, WM_KEYUP );
}

Basically, whenever you assign a derived to a base, this solution 
doesn't work, because T will be Base, not A.


I enjoyed with the previous code, so I wrote the code necessary 
to handle any WM_ message:


import core.sys.windows.windows;
import std.stdio;
import std.meta;

template startsWith(string prefix) {
enum startsWith(string s) = s.length >= prefix.length && 
s[0..prefix.length] == prefix;

}

enum getMessageValue(string s) = __traits(getMember, 
core.sys.windows.winuser, s);


// Get the all the WM_ messages
alias messageNames = Filter!(startsWith!"WM_", 
__traits(allMembers, core.sys.windows.winuser));
alias messageValues = NoDuplicates!(staticMap!(getMessageValue, 
messageNames));


class Base {
LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
foreach (msg; messageValues) {
case msg:
if (auto that = 
cast(IMessageHandler!msg)this) {

return that.handle(wParam, lParam);
}
break;
}
default:
}
return 0;
}
}

interface IMessageHandler(alias msg) {
mixin("LRESULT On"~__traits(identifier, msg)~"(WPARAM wParam, 
LPARAM lParam);");

alias handle = mixin("On"~__traits(identifier, msg));
}

class Button : Base, IMessageHandler!WM_KEYDOWN, 
IMessageHandler!WM_SETTINGCHANGE {

LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) {
writeln("WM_KEYDOWN");
return 0;
}
LRESULT OnWM_SETTINGCHANGE(WPARAM wParam, LPARAM lParam) {
writeln("WM_SETTINGCHANGE");
return 0;
}
}

unittest {
Base b1 = new Base();
Base b2 = new Button();

writeln("Base:");
// None of these will print anything, as Base doesn't handle 
them

b1.On(WM_KEYDOWN, 0, 0);
b1.On(WM_SETTINGCHANGE, 0, 0);
b1.On(WM_DRAWITEM, 0, 0);
writeln("Button:");
b2.On(WM_KEYDOWN, 0, 0);
b2.On(WM_SETTINGCHANGE, 0, 0);
// This will print nothing, as Button doesn't handle that 
message.

b2.On(WM_DRAWITEM, 0, 0);
}

--
  Simen


Re: Call method if declared only

2020-02-28 Thread Simen Kjærås via Digitalmars-d-learn

On Friday, 28 February 2020 at 09:25:58 UTC, Виталий Фадеев wrote:

Yes. Thank !
I read it.
Problem is - OS has many messages + user messages... It mean 
what interfaces like IKeyDown must me declared. All. Dream on 
write less code...


So let's create a template for that:

interface IMessageHandler(alias msg) {
mixin("LRESULT On"~__traits(identifier, msg)~"(WPARAM wParam, 
LPARAM lParam);");

}

And use it:

import core.sys.windows.windows;
import std.stdio;

class Base {
LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_KEYDOWN:
if (auto that = 
cast(IMessageHandler!WM_KEYDOWN)this) {

return that.OnWM_KEYDOWN(wParam, lParam);
}
break;
default:
}
return 0;
}
}

class Button : Base, IMessageHandler!WM_KEYDOWN {
LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) {
writeln("WM_KEYDOWN");
return 0;
}
}

unittest {
Base b1 = new Base();
Base b2 = new Button();

writeln("Base:");
b1.On(WM_KEYDOWN, 0, 0);
writeln("Button:");
b2.On(WM_KEYDOWN, 0, 0);
}

You'll still have to specify for each derived class which 
messages they handle, but no need to define hundreds of 
interfaces separately.


--
  Simen



Re: Call method if declared only

2020-02-28 Thread Simen Kjærås via Digitalmars-d-learn

On Friday, 28 February 2020 at 06:12:37 UTC, Виталий Фадеев wrote:

Searching solution for idea !


For whatever reason, it seems my attempts at answering this 
earlier has disappeared into the void. Here:


import core.sys.windows.windows;
import std.stdio;

class Base {
LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_KEYDOWN:
return tryCall!"OnWM_KEYDOWN"(wParam, lParam);
default:
}
return 0;
}

auto tryCall(string name, Args...)(Args args) {
import std.meta;

alias This = typeof(this);
alias module_ = __traits(parent, This);

enum isSubclass(T...) = is(T[0] : This);
alias getModuleMember(string name) = __traits(getMember, 
module_, name);

enum hasMethod(T) = __traits(hasMember, T, name);

// Get every member in this module
enum memberNames = __traits(allMembers, module_);
alias members = staticMap!(getModuleMember, memberNames);

// Filter away anything that isn't derived from Base
alias subclasses = Filter!(isSubclass, members);

// Get rid of anything that doesn't have a method with 
the correct name
alias subclassesWithMethod = Filter!(hasMethod, 
subclasses);


// Sort them so you get the most derived types first
alias Types = DerivedToFront!subclassesWithMethod;

// Check for each type if the `this` is an instance of 
that specific one

static foreach (T; Types) {
if (cast(T)this !is null) {
// And look up that method and call it.
return __traits(getMember, cast(T)this, 
name)(args);

}
}

// If `this` is not one of the types with that method, 
return some default value

return 0;
}
}

class Button : Base {
LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) {
writeln("WM_KEYDOWN");
return 0;
}
}

unittest {
Base b1 = new Base();
Base b2 = new Button();

writeln("Base:");
b1.On(WM_KEYDOWN, 0, 0);
writeln("Button:");
b2.On(WM_KEYDOWN, 0, 0);
}

Now, this only works for subclasses defined in the same module. A 
possibly better solution would be interfaces:


import core.sys.windows.windows;
import std.stdio;

class Base {
LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_KEYDOWN:
if (cast(IKeyDown)this) {
return 
(cast(IKeyDown)this).OnWM_KEYDOWN(wParam, lParam);

}
default:
}
return 0;
}
}

interface IKeyDown {
LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam);
}

class Button : Base, IKeyDown {
LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) {
writeln("WM_KEYDOWN");
return 0;
}
}

unittest {
Base b1 = new Base();
Base b2 = new Button();

writeln("Base:");
b1.On(WM_KEYDOWN, 0, 0);
writeln("Button:");
b2.On(WM_KEYDOWN, 0, 0);
}

--
  Simen


Re: Call method if declared only

2020-02-28 Thread Simen Kjærås via Digitalmars-d-learn

On Friday, 28 February 2020 at 08:08:59 UTC, Виталий Фадеев wrote:
On Friday, 28 February 2020 at 06:12:37 UTC, Виталий Фадеев 
wrote:

Searching solution for idea !

Goal is to get System message, dispatch/route to method !
If method implemented only !

I dream on in future write clean code of a derived widgets 
like this :


class Base
{
   // dispatch
   void On( message ... )
   {
   // call On()
   // example: call OnKeyUp() - if method OnKeyUp() is 
exists only

   }
}

May be other than derived ? May be templating ?
How to implement ?


Now I go in ths way:

[snip]

Searching for beauty readable code...


Here's an attempt. It looks up all subclasses of Base in the same 
module, and calls the named method if it exists. However, it will 
fail for any subclass of Base that is defined in a different 
module.


import core.sys.windows.windows;
import std.stdio;

class Base {
LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_KEYDOWN:
return tryCall!"OnWM_KEYDOWN"(wParam, lParam);
default:
}
return 0;
}

auto tryCall(string name, Args...)(Args args) {
import std.meta;

alias This = typeof(this);
alias module_ = __traits(parent, This);

enum isSubclass(T...) = is(T[0] : This);
alias getModuleMember(string name) = __traits(getMember, 
module_, name);

enum hasMethod(T) = __traits(hasMember, T, name);

// Get every member in this module
enum memberNames = __traits(allMembers, module_);
alias members = staticMap!(getModuleMember, memberNames);

// Filter away anything that isn't derived from Base
alias subclasses = Filter!(isSubclass, members);

// Get rid of anything that doesn't have a method with 
the correct name
alias subclassesWithMethod = Filter!(hasMethod, 
subclasses);


// Sort them so you get the most derived types first
alias Types = DerivedToFront!subclassesWithMethod;

// Check for each type if the `this` is an instance of 
that specific one

static foreach (T; Types) {
if (cast(T)this !is null) {
// And look up that method and call it.
return __traits(getMember, cast(T)this, 
name)(args);

}
}

// If `this` is not one of the types with that method, 
return some default value

return 0;
}
}

class Button : Base {
LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) {
writeln("WM_KEYDOWN");
return 0;
}
}

unittest {
Base b1 = new Base();
Base b2 = new Button();

writeln("Base:");
b1.On(WM_KEYDOWN, 0, 0);
writeln("Button:");
b2.On(WM_KEYDOWN, 0, 0);
}

--
  Simen


Re: How to copy const object?

2020-02-27 Thread Simen Kjærås via Digitalmars-d-learn

On Thursday, 27 February 2020 at 11:28:11 UTC, Mitacha wrote:
I've a const struct object and I'd like to make a mutable copy 
of it.

Struct definition contains string and an array of structs.
```
struct A {
string a;
B[] b;
}

struct B {
string a;
string b;
}
```
As far as I can tell copy constructor isn't generated for 
struct `A` because it contains an array. Correct?


Is there an idiomatic way to create copy of a const object?


As long as the copy is also const, you can just assign it to a 
new variable of the same type:


const A a = A("foo",[B("bar", "baz")]);
const A b = a;

If, however, you require a mutable copy, things get a little more 
hair. In D, const is transitive, so that A.b[0] is a const(B). 
This will thus not work:


A c = a; // Error: cannot implicitly convert expression a of 
type const(A) to A


For built-in arrays, the .dup function does this:

const int[] arr1 = [1];
int[] arr2 = arr1; // Fails to compile
int[] arr3 = arr1.dup; // Works

For symmetry, we can add a similar function to A:

struct A {
string a;
B[] b;
A dup() const {
return A(a, b.dup);
}
}

This lets us easily create a copy:

A d = a.dup;

Now, the reason you can't just assign from const(A) to A, while 
this works with const(B) to B, e.g., is that A contains mutable 
indirections. That is, you can change the contents of A.b. Since 
copies are generally shallow copies in D, allowing this behavior 
would have unfortunate consequences:


const(A) a1 = A("foo", [B("bar", "baz")]);
A a2 = a1; // Assume this worked
assert(a1.b[0].a == "bar");
a1.b[0].a = "qux"; // Can't change b[0] through a1, since 
it's const

a2.b[0].a = "qux"; // But we can change it through a2!
assert(a1.b[0].a != "bar"); // And suddenly the const value 
in a1.b has changed.


--
  Simen




Re: String switch is odd using betterC

2020-02-26 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 26 February 2020 at 08:32:50 UTC, Abby wrote:

On Wednesday, 26 February 2020 at 08:25:00 UTC, Abby wrote:

Any idea why?


Ok so this is enough to produce the same result, it seems that 
there is a problem in string switch when there is more the 6 
cases.


extern(C) void main()
{
auto s = "F";
final switch(s)
{
case "A": break;
case "B": break;
case "C": break;
case "D": break;
case "E": break;
case "F": break;
case "G": break;
}
}


The explanation can be found in 
druntime/import/core/internal/switch_.d: the __switch template 
does a simple binary search for less than 7 cases, but calls 
.idup on each case label for >= 7 cases.


There's a comment there about why it's being done, but it seems 
to be a far more complicated fix than necessary - static 
immutable cases = [caseLabels]; works just as well, it seems.


Anyway, the current code was added in this commit: 
https://github.com/dlang/druntime/commit/fa665f6618af7dbc09ed5ba1333f385017b7ece8.


Anyways, reported here: 
https://issues.dlang.org/show_bug.cgi?id=20613


--
  Simen


Re: Alternative to friend functions?

2020-02-18 Thread Simen Kjærås via Digitalmars-d-learn

On Tuesday, 18 February 2020 at 12:43:22 UTC, Adnan wrote:

class Wife(uint N) : Female {
FemaleID engagedTo = -1;
const MaleID[N] preferences;

this(MaleID[N] preferences) {
this.preferences = preferences;
}
}

void engage(N)(ref Wife!N, wife, ref Husband!N husband) {
// Here, I want to access both husband and wife's engaged_to
}


Petar's answer covers your question, so I won't elaborate on 
that, but I'd like to point out that as Wife and Husband are 
classes, you probably don't intend to take them by ref - classes 
are always by ref in D, so you're effectively passing a reference 
to a reference to a class in `engage`.


Basically:

class Foo {
int n;
}

void fun(Foo f) {
f.n = 3;
// Local copy of the reference - does not modify other 
references.

f = null;
}

void gun(ref Foo f) {
f = null;
}

unittest {
Foo f = new Foo();
Foo g = f;
f.n = 17;
// f and g point to the same object:
assert(f.n == 17);
assert(g.n == 17);

fun(f);
// fun() changed the object that both f and g point to:
assert(f.n == 3);
assert(g.n == 3);

gun(f);
// gun() changed f to no longer point at the same object, but 
left g untouched:

assert(f is null);
assert(g !is null);
assert(g.n == 3);
}

--
  Simen


Re: How to declare a virtual member (not a function) in a class

2020-02-18 Thread Simen Kjærås via Digitalmars-d-learn

On Tuesday, 18 February 2020 at 12:37:45 UTC, Adnan wrote:
I have a base class that has a couple of constant member 
variables. These variables are abstract, they will only get 
defined when the derived class gets constructed.


class Person {
const string name;
const int id;
}

class Male : Person {
this(string name = "Unnamed Male") {
static int nextID = 0;
this.id = nextID++;
this.name = name;
}
}

The compiler restricts me from assigning those two functions. 
How can I get around this?


const members can only be set in the constructor of the type that 
defines them. To set them in a subclass, forward the values to 
the superclass' constructor:


class Person {
const string name;
const int id;
protected this(string _name, int _id) {
id = _id;
name = _name;
}
}

class Male : Person {
this(string name = "Unnamed Male") {
static int nextID = 0;
super(name, nextID++);
}
}

--
  Simen


Re: Why can't I pass a const array to a function that takes scope const arrays?

2020-02-17 Thread Simen Kjærås via Digitalmars-d-learn

On Monday, 17 February 2020 at 14:04:34 UTC, Adnan wrote:

cdsa ~master: building configuration "cdsa-test-library"...
source/strassens_matmul.d(22,16): Error: cannot implicitly 
convert expression [row][column] of type const(uint)* to 
uint*
source/strassens_matmul.d(37,36): Error: template instance 
strassens_matmul.getPointPtr!uint error instantiating

source/strassens_matmul.d(48,29):


I'd just finished writing a long post explaining the stuff you've 
apparently figured out. Ah well. :p


In this case, getPointPtr return T*, but takes scope const ref 
T[][]. Since getPointPtr always takes a mutable array, you could 
just get rid of const on its parameters. Alternatively, if you 
want to be able to use it on arrays of different constness, you 
could use inout:


inout(T)* getPointPtr(T)(inout T[][] mat, size_t row, size_t 
column) {


This will return a pointer to a mutable T if that's what the 
array holds when you call the function, const(T) if it's a const 
array, immutable(T) if it's immutable, and so on.


The same can be done with the other functions you have.

You are also somewhat overusing const, scope and ref, I'd say - 
you should not take an array by ref unless you plan on modifying 
it, which you are not doing in getPointPtr or any other of your 
functions. scope may be worth it, as it guarantees you won't be 
sending the data elsewhere.


None of these are necessary on your ulongs, which are passed by 
value and never attempted modified. If you really like the extra 
guarantee that you don't accidentally modify them, feel free to 
keep 'const', but 'scope' on a ulong does nothing, and it's been 
argued it should be a compiler error.


Lastly, you're using ulongs a lot, and this is mostly correct 
when compiling for 64-bit, but makes code fail to compile for 
32-bit. Using size_t instead makes for code that works for both.


All in all, I end up with this code:

module strassens_matmul;

debug {
static import std;
}

package {
size_t getRowSize(T)(const T[][] mat) {
return mat[0].length;
}

size_t getColumnSize(T)(const T[][] mat) {
return mat.length;
}

T[][] createMatrix(T)(size_t rowSize, size_t columnSize) {
return new T[][](rowSize, columnSize);
}

/// row and column are 0 index-based
inout(T)* getPointPtr(T)(inout T[][] mat, size_t row, size_t 
column) {

return [row][column];
}

T getPointCopy(T)(const T[][] mat, size_t row, size_t column) 
{

return mat[row][column];
}

T[][] mulIterative(T)(const T[][] mat1, const T[][] mat2) {
auto result = createMatrix!T(getRowSize!T(mat1), 
getColumnSize!T(mat2));

foreach (row; 0 .. mat1.getRowSize()) {
foreach (column; 0 .. mat2.getColumnSize()) {
T value;
foreach (i; 0 .. mat1.getRowSize()) {
value += mat1.getPointCopy(row, i) * 
mat2.getPointCopy(i, column);

}
*result.getPointPtr(row, column) = value;
}
}
return result;
}
}

unittest {
const uint[][] matA = [[10, 20, 10], [4, 5, 6], [2, 3, 5]];
const uint[][] matB = [[3, 2, 4], [3, 3, 9], [4, 4, 2]];
const uint[][] matC = [[130, 120, 240], [51, 47, 73], [35, 
33, 45]];

assert(matA.mulIterative(matB) == matC);
}

--
  Simen


Re: operator overload for sh-like scripting ?

2020-02-17 Thread Simen Kjærås via Digitalmars-d-learn

On Monday, 17 February 2020 at 13:03:38 UTC, Basile B. wrote:

eg

   Sh(echo) < "meh";

struct Sh
{
 // you see the idea we have op overload for < here
}


You can't overload < separately - all the comparison operators 
(<, <=, >, >=) are handled via opCmp. Even if you choose to go 
down that route, there are other issues - opCmp needs to return 
something that may be compared to 0, since (a < b) is rewritten 
as (a.opCmp(b) < 0), and the compiler checks if you are simply 
discarding the return value of a comparison, so all in all, you 
shouldn't do that in D (and the hoops you have to jump through to 
make it work makes the code a lot less readable):


struct Sh {
int opCmp(string s) {
import std.stdio : writeln;
writeln(s);
return 0;
}
}

unittest {
Sh sh;
auto _ = sh < "baz";
}

This is also not chainable, so something like (sh < "foo" < 
"bar") won't work, even with parentheses.


There's also the issue of (a < b) having a defined meaning in D 
(a less than b), and such overloading leads to code that may be 
less readable. This is a point with differing opinions, and I'm 
not firmly on either side of that argument, but it's worth 
pointing out.


Now, if you absolutely want something that's somewhat similar in 
regular D code, there's <<:


struct Sh {
Sh opBinary(string op : "<<")(string s) {
import std.stdio : writeln;
writeln(s);
return this;
}
}

unittest {
Sh sh;
sh << "foo" << "bar";
}

While this works, it's a design choice that C++ has gotten a lot 
of flak for, including one of my favorite C++ quotes: "I saw 
'cout' being shifted 'Hello world' times to the left and stopped 
right there." There are cases where it's not at obvious to the 
reader of the code what's happening, so such operator overloading 
should be used with caution.


A better choice, perhaps, if using < is important, would be to 
use a DSL and have it obvious in the code that normal D rules 
aren't at play:


void fun() {
Sh sh;
mixin dsl!`
sh < "foo";
`;
}

At this point though, you're looking at a considerable chunk of 
code just for a bit of syntactic sugar.


--
  Simen


Re: From [Tuple!(A,B), ...] to Tuple!(A[], B[])

2020-02-17 Thread Simen Kjærås via Digitalmars-d-learn
On Monday, 17 February 2020 at 11:51:52 UTC, FeepingCreature 
wrote:

Here you go:

import std;

// extract the types that make up the tuple
auto transposeTuple(T : Tuple!Types[], Types...)(T tuples)
{
// templated function that extracts the ith field of an 
array of tuples as an array

auto extractArray(int i)()
{
return tuples.map!(a => a[i]).array;
}
// return tuple of calls to extractArray, one for each 
tuple index
return tuple(staticMap!(extractArray, 
aliasSeqOf!(Types.length.iota)));

}

void main() {
Tuple!(int, double)[] array;
array ~= tuple(1, 2.0);
array ~= tuple(3, 4.0);
Tuple!(int[], double[]) tuple = array.transposeTuple;
assert(tuple[0] == [1, 3]);
assert(tuple[1] == [2.0, 4.0]);
}


One tiny thing: the above fails for tuples with named fields, 
like Tuple!(int, "a", string "b"). This code handles that case, 
and preserves field names:


import std.meta : staticMap, aliasSeqOf;
import std.typecons : Tuple;
import std.range : array, iota;
import std.algorithm : map;

alias ToArray(T) = T[];
alias ToArray(T...) = T;
alias ToArrayTuple(T : Tuple!U, U...) = 
Tuple!(staticMap!(ToArray, U));


auto transpose(T : Tuple!U, U...)(T[] arr) {
auto extract(int i)() { return arr.map!(a => a[i]).array; }
return ToArrayTuple!T(staticMap!(extract, 
aliasSeqOf!(T.Types.length.iota)));

}

unittest {
alias T = Tuple!(int, "a", string, "b");
auto a = [T(1, "a"), T(2, "b")];
assert(a.transpose.a == [1, 2]);
assert(a.transpose.b == ["a", "b"]);
}

--
  Simen


Re: From [Tuple!(A,B), ...] to Tuple!(A[], B[])

2020-02-17 Thread Simen Kjærås via Digitalmars-d-learn
On Monday, 17 February 2020 at 11:51:52 UTC, FeepingCreature 
wrote:

On Monday, 17 February 2020 at 11:07:33 UTC, foozzer wrote:

Hi all,

There's something in Phobos for that?

Thank you


Here you go:

import std;

// extract the types that make up the tuple
auto transposeTuple(T : Tuple!Types[], Types...)(T tuples)
{
// templated function that extracts the ith field of an 
array of tuples as an array

auto extractArray(int i)()
{
return tuples.map!(a => a[i]).array;
}
// return tuple of calls to extractArray, one for each 
tuple index
return tuple(staticMap!(extractArray, 
aliasSeqOf!(Types.length.iota)));

}

void main() {
Tuple!(int, double)[] array;
array ~= tuple(1, 2.0);
array ~= tuple(3, 4.0);
Tuple!(int[], double[]) tuple = array.transposeTuple;
assert(tuple[0] == [1, 3]);
assert(tuple[1] == [2.0, 4.0]);
}


^^ Do what he said - I misread the title. :)

--
  Simen


Re: From [Tuple!(A,B), ...] to Tuple!(A[], B[])

2020-02-17 Thread Simen Kjærås via Digitalmars-d-learn

On Monday, 17 February 2020 at 11:07:33 UTC, foozzer wrote:

Hi all,

There's something in Phobos for that?

Thank you


import std.meta : staticMap;
import std.typecons : Tuple;

// Turn types into arrays
alias ToArray(T) = T[];
// Leave everything else the same
alias ToArray(T...) = T;
// Now apply the above to each element of the Tuple template args:
alias ToArrayTuple(T : Tuple!U, U...) = 
Tuple!(staticMap!(ToArray, U));


unittest {
alias A = Tuple!(int, string);
assert(is(ToArrayTuple!A == Tuple!(int[], string[])));
alias B = Tuple!(int, "a", string, "b");
assert(is(ToArrayTuple!B == Tuple!(int[], "a", string[], 
"b")));

}

--
  Simen


Re: Global version/debug statements in file?

2020-02-12 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 12 February 2020 at 08:44:24 UTC, cc wrote:
Is there some way to globally declare version= or debug= 
statements in a file and have them apply to the entire project 
being compiled?  As the documentation says these only apply to 
the module scope they exist in, and need to be added to the 
command line otherwise.  It would be a bit easier for me to 
maintain a separate .d source file when I want to add/comment 
out statements for testing than to keep updating the build 
command line.


https://dlang.org/dmd-windows.html#switches

specifies that DMD may be passed a file on the command line that 
contains compiler arguments and switches. This may be freely 
combined with regular command line arguments if you so wish.


So, you could have a file called 'versions' containing this:

# Setting 'Compress' version
-version=Compress
# Optionally set other versions
#-version=Foo
#-version=Bar

and feed it to dmd like so:

dmd -w -wi -g @versions -main foo.d

--
  Simen


Re: Custom separator in array format

2020-01-28 Thread Simen Kjærås via Digitalmars-d-learn

On Tuesday, 28 January 2020 at 07:36:25 UTC, Malte wrote:
I want to format an array using the %(...%) syntax. How can I 
change the separator? I tried to use ? and add it as additional 
parameter, but that doesn't seem to work on arrays:


import std;
void main()
{
writeln("This works:");
writefln("%,2?d", '_', 2000); // 20_00

auto vec = [1000, 2000, 3000];
writeln("This should fail (separator character expected) 
but the ? is just ignored:");

writefln("%(%,2?d\t%)", vec); // 10,0020,00   30,00
writeln("This throws:");
writefln("%(%,2?d\t%)", '_', vec); // 
std.format.FormatException@/dlang/dmd/linux/bin64/../../src/phobos/std/format.d(2271): incompatible format character for integral argument: %(

}


I think I see why it's not working. Essentially, for each element 
of vec, format is called with only that element as an argument. 
Essentially, rather than:


foreach (e; vec)
writef("%,2?d\t", '_', e);
writeln();

You get:

foreach (e; vec)
writef("%,2?d\t", e);
writeln();

For whatever reason, it doesn't throw when missing an argument 
for the separator - I'd say this is a bug 
(https://issues.dlang.org/show_bug.cgi?id=20541).


For now, you can work around the issue this way:

import std.stdio : writefln;
import std.format : format;
import std.algorithm : map;

auto vec = [1000, 2000, 3000];

writefln("%-(%s\t%)", vec.map!(e => format!"%,2?d"('_', e)));

--
  Simen


Re: @disable("reason")

2020-01-08 Thread Simen Kjærås via Digitalmars-d-learn
On Wednesday, 8 January 2020 at 07:03:26 UTC, Jonathan M Davis 
wrote:

you could just document that no one should ever use its init
value explicitly, and that they will have bugs if they do


You also create a static init member marked @disable:

struct S {
@disable this();
@disable static S init();
}

This will give sensible error messages anywhere .init is being 
used. Now, Phobos and other libraries might expect that .init is 
always working, so this could potentially be a problem.


Re: @disable("reason")

2020-01-08 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 8 January 2020 at 08:26:51 UTC, user1234 wrote:

class Example
{
@disable this() { pragma(msg, "not allowed..."); }
}

void main()
{
new Example();
}

outputs:


not allowed...
/tmp/temp_7F8C65489550.d(12,5): Error: constructor 
`runnable.Example.this` cannot be used because it is annotated 
with `@disable`


However, it will print that message even if the constructor is 
never called. If you make the constructor a template instead, you 
will only get the message when someone attempts to use the 
default constructor:


class Example
{
@disable this()() { pragma(msg, "not allowed..."); }
}

void main()
{
new Example();
}

Sadly, this does not work for structs, as they don't really have 
a default constructor, as Jonathan pointed out.


--
  Simen


Re: Should I stop being interested in D language if I don't like to see template instantiation in my code?

2019-11-14 Thread Simen Kjærås via Digitalmars-d-learn

On Thursday, 14 November 2019 at 09:30:23 UTC, user9876 wrote:
A good thing is that in many cases the template instance 
parameters can be deduced from the arguments used:


---
import std;

void main()
{
assert(max(0,1) == 1);
// same as assert(max!(int,int)(0,1) == 1);
}
---

This feature is known as "IFTI" see §6, 
https://dlang.org/spec/template.html#function-templates.


You're not forced to use the D templates but you'll have to 
write many code by yourself because the standard library use 
them everywhere.


IFTI is nifty. (sorry, I had to)

--
  Simen


  1   2   3   4   >