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


Re: How decode encoded Base64 to string text?

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

On Friday, 8 November 2019 at 11:46:44 UTC, Marcone wrote:
I can encode "Helo World!" to Base64 and get "TWFyY29uZQ==", 
but if I try to decode "TWFyY29uZQ==" I can not recovery "Helo 
World!" but [77, 97, 114, 99, 111, 110, 101]. How can I recover 
"Helo World!" when decode? Thank you.



import std;

void main(){
string text = "Helo World!";

auto encoded = Base64.encode(text.representation);
auto decoded = Base64URL.decode("TWFyY29uZQ==");

writeln(encoded); // prints: "TWFyY29uZQ=="
	writeln(to!string(decoded)); // prints: [77, 97, 114, 99, 111, 
110, 101] but I want to print: "Helo World!"

}


What Aldo said - Base64 operates on ubyte[], which a string is 
not (it's immutable(char)[]). There's also assumeUTF 
(https://dlang.org/library/std/string/assume_utf.html) which may 
document your code a bit better than a simple cast, but it does 
the same thing inside.


The reason Base64 operates on ubyte[] is to be able to encode 
arbitrary data, while the reason to!string doesn't convert your 
ubyte[] to a readable string is that not all ubyte[] are valid 
strings, and displaying arbitrary data as if it were a string is 
sure to cause problems.


--
  Simen


Re: Bug or Feature: `this` necessary to call function with template this parameter

2019-10-30 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 30 October 2019 at 20:22:25 UTC, Q. Schroll wrote:

struct Example
{
private void helper(int i, this X)() { }
void funcTempl(T, this X)(T value)
{
this.helper!0();
//  ^ Why do I need this?
}
}

void main()
{
auto ex = Example();
ex.funcTempl(1);
}

The question is in the comment in the code. Is that intentional 
or a bug?


It's a bug - filed as 
https://issues.dlang.org/show_bug.cgi?id=20341.


However, note that typeof(this) inside funcTempl() is different 
from X, so that inside helper(), X will not be the same as in 
funcTempl(). To fix this, you will need to pass X on to helper as 
helper!(0, X). When you do this, you no longer need 'this.' in 
front of the instantiation.


--
  Simen


Re: Read Once then reset/init value?

2019-10-30 Thread Simen Kjærås via Digitalmars-d-learn
On Wednesday, 30 October 2019 at 11:53:42 UTC, Jacob Carlborg 
wrote:

On 2019-10-30 00:28, Simen Kjærås wrote:


Something like this?

T readOnce(T)(ref T value) {
     auto tmp = value;
     value = T.init;
     return tmp;
} unittest {
     int i = 3;
     assert(i.readOnce == 3);
     assert(i == 0);
}


Perhaps better to encapsulate it in a struct to avoid someone 
accessing the value directly.


Quite possibly, but the post was somewhat low on details, and 
encapsulating it like that does put certain limits on how it can 
be used, so it's not necessarily the best idea.


FWIW, here's one possible way to do it with a struct:

struct Readonce(T, T defaultValue = T.init) {
private T value;

alias get this;

T get() {
auto tmp = value;
value = defaultValue;
return tmp;
}

void get(T newValue) {
value = newValue;
}

this(T newValue) {
value = newValue;
}
}

unittest {
Readonce!(int, -1) a = 3;
assert(a == 3);
assert(a == -1);

a = 3;
assert(a == 3);
assert(a == -1);
}

--
  Simen


Re: Read Once then reset/init value?

2019-10-29 Thread Simen Kjærås via Digitalmars-d-learn
On Tuesday, 29 October 2019 at 22:24:20 UTC, Robert M. Münch 
wrote:
I quite often have the pattern where a value should be read 
just once and after this reset itself. The idea is to avoid 
that others read the value by accident and get an older state, 
instead they get an "invalid/reset" value.


Is there a library function that can mimic such a behaviour?


Something like this?

T readOnce(T)(ref T value) {
auto tmp = value;
value = T.init;
return tmp;
} unittest {
int i = 3;
assert(i.readOnce == 3);
assert(i == 0);
}

If so, no, there is no library function for it, but feel free to 
use the above. You may very well have to change T.init to 
something more fitting for your use case, of course.


If this is not what you need, feel free to explain further, as 
I'm not sure I understood you correctly. :)


--
  Simen


Re: The compiler can't "see" an inner class

2019-10-27 Thread Simen Kjærås via Digitalmars-d-learn

On Sunday, 27 October 2019 at 17:52:51 UTC, Emmanuelle wrote:

Hello! See snippet:

---
interface AST
{
static interface Expr : AST
{
final static class Name : Expr
{
override void accept(AST.Visitor v) { 
v.visitName(this); }

}
}

final static class Visitor
{
void visitName(AST.Expr.Name name);
}

void accept(AST.Visitor v);
}
---

If you try to compile that, dmd v2.088.0 complains:

---
Error: no property Name for type onlineapp.AST.Expr
---

How come? It's defined right there. I would really like some 
pointers on this, thanks!


It's a bug:

interface A {
interface B : A {
class C : B {
}
}
// Fails: no property 'C' for type 'foo.A.B'
void inside(A.B.C c) { }
}
// Works
void outside(A.B.C c) { }

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

--
  Simen


Re: A proper WAT moment

2019-10-15 Thread Simen Kjærås via Digitalmars-d-learn

On Tuesday, 15 October 2019 at 07:06:35 UTC, John Colvin wrote:

On Monday, 14 October 2019 at 19:45:11 UTC, Paul Backus wrote:

On Monday, 14 October 2019 at 17:00:56 UTC, John Colvin wrote:
Different ability to access a property depending if I'm 
inside something else when I look?


[snip]


You're attempting to call one of S's member functions without 
an instance of S to call it on.

[snip]
The real issue here is that the first `__traits(compiles)` 
check succeeds, even though the actual expression fails.


And all the other ones in my example that access members 
without an instance that also compile?


There's something pretty strange about the rules here.


Yeah, Paul's wrong here - the struct is what messes things up 
here, though I don't understand why. Just putting the first 
function inside a struct cause the exact same issue:


struct S {
int a;
int e() @property { return a; }
}

pragma(msg, __LINE__, " ", __traits(compiles,__traits(getMember, 
S, "e")));


void fun() {
pragma(msg, __LINE__, " ", 
__traits(compiles,__traits(getMember, S, "e")));

}

struct S2 {
void fun() {
pragma(msg, __LINE__, " ", 
__traits(compiles,__traits(getMember, S, "e")));

}
}

Interestingly, the code does of course actually compile:

struct S3 {
void fun() {
alias a = __traits(getMember, S, "e");
}
}


Re: Problem with using std.math: abs and std.complex: abs at the same time

2019-09-19 Thread Simen Kjærås via Digitalmars-d-learn

On Thursday, 19 September 2019 at 10:25:01 UTC, berni wrote:
On Thursday, 19 September 2019 at 07:26:17 UTC, Simen Kjærås 
wrote:
That does indeed fail to compile, and there's no easy way to 
introduce the module-level abs() function to the scope. Again 
though, MergeOverloads to the rescue:


I'm not sure, if MergeOverloads will be accepted into 
std/math.d. Meanwhile I've created a pull request (#7187), that 
does not handle complex numbers although the algorithm would be 
identical. Maybe handling complex numbers in math.d can be 
added later (or maybe it's better to put this in std/complex.d 
anyway, but then code duplication would be necessary).


You could perfectly well place MergeOverloads inside whatever 
function you make, thus not polluting std.math:


float abs(float f) {
return f < 0 ? -f : f;
}

unittest {
import std.complex : complex, cabs = abs;
template MergeOverloads(T...) {
static foreach (E; T)
alias MergeOverloads = E;
}
alias abs = MergeOverloads!(cabs, .abs);
abs(1);
abs(complex(1,1));
}

(you can also use this to create ridiculous overload sets, since 
MergeOverloads doesn't care if one function is called abs and the 
other dropBackExactly. Please don't do this)


If you want to introduce MergeOverloads to Phobos officially, 
std.math is definitely *not* the place though. :)


I'd probably say std.functional, but I'm not really sure where 
it'd belong. Let's put it in std.exception, since it's an 
exception from D's usual overload rules in functions. :p


I don't think anything in std.math explicitly deals with 
std.complex at this point (some things may handle it 
generically), so it seems std.complex would be the logical place 
for anything that does. Might I ask what specifically you're 
working on?


--
  Simen


Re: Problem with using std.math: abs and std.complex: abs at the same time

2019-09-19 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 18 September 2019 at 13:24:05 UTC, berni wrote:
On Wednesday, 18 September 2019 at 12:37:28 UTC, Simen Kjærås 
wrote:
How to resolve this, though? The simplest solution is to not 
use selective imports:


import std.math;
import std.complex;

writeln(abs(complex(1.0,1.0)));
writeln(abs(1.0));


That works. But: I'm trying to write some code for math.d and 
when I put this code inside math.d it doesn't work anymore. 
Also removing "import std.math" or moving it after the other 
import, did not help.


So what you have is basically this?

import std.stdio;

float abs(float f) {
return f >= 0 ? f : -f;
}

unittest {
import std.complex : complex, abs;

auto a = complex(1.0,1.0);
auto b = 1.0f;

writeln(abs(a));
writeln(abs(b));
}

That does indeed fail to compile, and there's no easy way to 
introduce the module-level abs() function to the scope. Again 
though, MergeOverloads to the rescue:


float abs(float f) {
return f < 0 ? -f : f;
}

unittest {
import std.complex : complex, cabs = abs;
alias abs = MergeOverloads!(cabs, .abs);
abs(1);
abs(complex(1,1));
}

template MergeOverloads(T...) {
static foreach (E; T)
alias MergeOverloads = E;
}

--
  Simen


Re: Problem with using std.math: abs and std.complex: abs at the same time

2019-09-18 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 18 September 2019 at 12:03:28 UTC, berni wrote:

The following code doesn't compile:


import std.stdio;

void main()
{
   import std.complex: abs, complex;
   import std.math: abs;

   auto a = complex(1.0,1.0);
   auto b = 1.0;

   writeln(abs(a));
   writeln(abs(b));
}


The error message depends on the order of the two import 
statements. Seems like the second import is actually ignored.


import std.complex: abs, complex;

Is treated by the compiler as if you'd written something somewhat 
like this:


static import std.complex;
alias abs = std.complex.abs;
alias complex = std.complex.complex;

When you add

import std.math: abs;

It's treated like:

static import std.math;
alias abs = std.math.abs;

In other words, we have two aliases with the same name inside a 
function scope, and the compiler can't do that (try doing it 
explicitly, as in the 'treated like' sections above - you'll get 
a compilation error). This is related to why you can't have 
overloaded nested functions:


unittest {
void fun() {}
void fun(int i) {} // declaration fun is already defined
}

How to resolve this, though? The simplest solution is to not use 
selective imports:


import std.math;
import std.complex;

writeln(abs(complex(1.0,1.0)));
writeln(abs(1.0));

If you absolutely can't contaminate the scope with all the unused 
symbols in std.math and std.complex, you *can* do this:


import std.stdio;

unittest {
import std.complex : complex;
static import std.math;

alias abs = MergeOverloads!(std.complex.abs, std.math.abs);

auto a = complex(1.0,1.0);
auto b = 1.0;

writeln(abs(a));
writeln(abs(b));
}

template MergeOverloads(T...) {
alias MergeOverloads = T[0];
static if (T.length > 1) {
alias MergeOverloads = MergeOverloads!(T[1..$]);
}
}

I would however label that a horrible hack.

FWIW, I've filed this issue: 
https://issues.dlang.org/show_bug.cgi?id=20226


--
  Simen


Re: default values depending on type of template variable

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

On Wednesday, 11 September 2019 at 08:35:02 UTC, berni wrote:
I'd like to write a template, that takes a different default 
value depending on the type of a variable. I tried this, but it 
doesn't work:



void main()
{
   double a = 1e-8;
   double b = 1e-10;
   float c = 1e-4;
   float d = 1e-6;

   assert(!test(a));
   assert(test(b));
   assert(!test(c));
   assert(test(d));
}

auto test(T, U)(T value, U limit=1e-9)
{
   return value

Although being called with a double in the first two tests, the 
second overload is always used and therefore the first test 
fails. And without this overload, the last test obviously 
doesn't pass.


Is there a way, to provide default values for template 
parameters depending on the type of an other parameter?


unittest
{
double a = 1e-8;
double b = 1e-10;
float c = 1e-4;
float d = 1e-6;

assert(!test(a));
assert(test(b));
assert(!test(c));
assert(test(d));
}


auto test(T, U)(T value, U limit = limit!T) {
return value < limit;
}

// Solution 1:
template limit(T) {
static if (is(T == float)) {
enum limit = 1e-5;
} else {
enum limit = 1e-9;
}
}

// Solution 2:
enum limit(T : float)  = 1e-5;
enum limit(T : double) = 1e-9;

With some tricks this can also be inlined:

enum If(bool b, T...) = T[b ? 0 : 1];
auto test(T, U)(T value, U limit = If!(is(T == float), 1e-5, 
1e-9)) {

return value < limit;
}

--
  Simen


Re: getting rid of immutable (or const)

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

On Thursday, 5 September 2019 at 09:07:30 UTC, berni wrote:

import std.algorithm: reverse;
writeln(q.reverse);


How to get this working? (I hope I don't annoy you by asking 
that much questions, but I've got the feeling, that I've got 
only two choices: To shy away from using immutable (like I did 
in the last three years) or ask a lot of questions in the hope 
of understanding what's going on...


https://dlang.org/library/std/range/retro.html

Difference is, retro lazily iterates in reverse order, while 
reverse eagerly reverses in-place.


Don't worry about asking questions - it's a good way to learn, 
and we like helping. :) Immutable is not very well supported 
everywhere in the library, sadly. It seems an important building 
block would be something like Reassignable!T, which would hold a 
struct with immutable members, and still be reassignable with 
different values.


--
  Simen


  1   2   3   4   >