Re: Using const to Enforce Design Decisions

2019-03-25 Thread Rubn via Digitalmars-d-announce

On Monday, 25 March 2019 at 13:00:07 UTC, Mike Parker wrote:
Marco de Wild has penned a tutorial on D's const for the D 
blog. He gives an overview of the feature, how it differs from 
C++, and shows how he employed it in his mahjong game.


The blog:
https://dlang.org/blog/2019/03/25/using-const-to-enforce-design-decisions/

Reddit:
https://www.reddit.com/r/programming/comments/b5a9jm/using_const_in_d_to_enforce_design_decisions/


I guess obligatory 
http://jmdavisprog.com/articles/why-const-sucks.html


Would be nice to see the source code for this mahjong game as 
well.


Re: DIP 1016--ref T accepts r-values--Formal Assessment

2019-01-31 Thread Rubn via Digitalmars-d-announce

On Thursday, 31 January 2019 at 22:00:10 UTC, Walter Bright wrote:

On 1/31/2019 1:46 PM, Andrei Alexandrescu wrote:
The proposal could actually disallow rvalues that have lvalue 
syntax, such as "symbol", "symbol[expr]", "symbol.symbol", 
"symbol.symbol[expr]", etc. Ugh. Gets hairy quickly.


That's why it's problematic to have a rule that rvalues can be 
implicitly converted, but not lvalues. There's not a hard line 
between lvalues and rvalues. For example,


  foreach(i; 0..2)
  {
int[] a = [1, 2];
assert(a[0] == 1]);
a[0] = 3;  // will this cause the assert to fail?
  }


Why would it cause the assert to fail? A new array is constructed 
each loop.


Re: DIP 1016 should use expression lowering, not statement lowering

2019-01-29 Thread Rubn via Digitalmars-d-announce
On Tuesday, 29 January 2019 at 15:44:02 UTC, Nicholas Wilson 
wrote:
On Tuesday, 29 January 2019 at 11:52:40 UTC, Andrei 
Alexandrescu wrote:

While writing this example:

int[] a = cast(int[]) alloc.allocate(100 * int.sizeof);
if (alloc.reallocate(a, 200 * int.sizeof))
{
assert(a.length == 200);
}

=>

int[] a = cast(int[]) alloc.allocate(100 * int.sizeof);
void[] __temp0 = a;
if (alloc.reallocate(__temp0, 200 * int.sizeof)
{
assert(a.length == 200);
}

I noticed a problem - the lowering as informally described in 
DIP 1016 makes it difficult to figure how function calls 
present in control statements like if, while, etc. should 
behave. Where should the temporary go? An expression-based 
lowering clarifies everything. A statement-based lowering 
would need to work on a case basis for all statements 
involving expressions.


On the contrary, an expression lowering cannot inject temporary 
declarations and is impossible.


The correct lowering in the case for `if` & friends follows the 
form of C++ initialiser conditions(?) i.e:


 if (auto val = expr(); val) { ... },

 or the slightly more ugly valid D:

 if ((){return expr(); }()) { ... }

this lambdification will work for just about anything: if, 
while, assert...


If it a condition then you can do the following in C++:

if(int* val = expr()) {
   // use val, not nullptr
}

Where it is useful is in the following case:

if(int val = expr(); val != -1) {

}

D follows C++'s construct for initializing a variable in control 
blocks. The only exception I think is for switch.


switch(int val = expr()) // ok in C++, not ok in D
{
}


Re: DIP 1016--ref T accepts r-values--Formal Assessment

2019-01-26 Thread Rubn via Digitalmars-d-announce

On Saturday, 26 January 2019 at 06:15:22 UTC, Walter Bright wrote:

On 1/25/2019 7:44 PM, Manu wrote:

I never said anything about 'rvalue references',


The DIP mentions them several times in the "forum threads" 
section. I see you want to distinguish the DIP from that; I 
recommend a section clearing that up.


However, my points about the serious problems with @disable 
syntax remain.


A section comparing with the C++ solution is necessary as well, 
more than the one sentence dismissal. For example, how C++ 
deals with the:


void foo(const int x);
void foo(const int& x);

situation needs to be understood and compared. Failing to 
understand it can lead to serious oversights. For example, C++ 
doesn't require an @disable syntax to make it work.




[...]
Should `s` be promoted to an int temporary, then pass the 
temporary by
reference? I can find no guidance in the DIP. What if `s` is 
a uint (i.e. the
implicit conversion is a type paint and involves no 
temporary)?

As per the DIP; yes, that is the point.
The text you seek is written: "[...]. The user should not 
experience
edge cases, or differences in functionality when calling 
fun(int x) vs

fun(ref int x)."


I don't see how that addresses implicit type conversion at all.


Anything that could be implicitly converted to use foo(int) can 
be implicitly converted to pass a ref to the temporary that was 
implicitly converted to int into foo(ref int). No rules change in 
this regard. If you don't see how this address type conversion 
perhaps a code sample might help? The one that was given with 
short:


void foo(ref int);
void bar(int);

bar( short(10) ); // is ok
foo( short(10) ); // expected to be ok short->int ; ref to temp 
passed to foo


Just as bar(int) can be passed a short(10), foo(ref int) can be 
passed a reference to the temporary that was created as well.



Don't accept naked ref unless you want these semantics. There 
is a
suite of tools offered to use where this behaviour is 
undesirable.

Naked `ref` doesn't do anything particularly interesting in the
language today that's not *identical* semantically to using a 
pointer

and adding a single '&' character at the callsite.


It's not good enough. The DIP needs to specifically address 
what happens with implicit conversions. The reader should not 
be left wondering about what is implied. I often read a spec 
and think yeah, yeah, of course it must be that way. But it is 
spelled out in the spec, and reading it gives me confidence 
that I'm understanding the semantics, and it gives me 
confidence that whoever wrote the spec understood it.


(Of course, writing out the implications sometimes causes the 
writer to realize he didn't actually understand it at all.)


Furthermore, D has these match levels:

1. exact
2. const
3. conversion
4. no match

If there are two or more matches at the same level, the 
decision is made based on partial ordering. How does adding the 
new ref/value overloading fit into that?


The DIP goes over this, though not in a lot of detail. All the 
same rules apply as with the current implementation. Where there 
would be a compiler error trying to pass an rvalue would instead 
forward the value.


Effectively what is being implemented is the following (for type 
matching only):


   void foo( ref int );
   void foo( int value ) { foo( value ); }

Anything that would have been passed to foo(int) is passed to 
foo(ref int) as a reference to a temporary instead. No rules are 
changed in this regard for matching, all the same rules apply (as 
stated in the DIP). It's pretty clear, unless you can give a 
specific problem faced where this doesn't hold? D is pretty 
strict to ensure rvalues aren't passed to ref's and that's what 
makes this relatively simple to implement without changing 
matching rules.




Re: DIP 1016--ref T accepts r-values--Formal Assessment

2019-01-25 Thread Rubn via Digitalmars-d-announce

On Friday, 25 January 2019 at 11:56:58 UTC, Walter Bright wrote:

On 1/24/2019 11:53 PM, Nicholas Wilson wrote:
That the conflation of pass by reference to avoid copying and 
mutation is not only deliberate but also mitigated by @disable.


The first oddity about @disable is it is attached to the 
foo(int), not the foo(ref int). If I wanted to know if foo(ref 
int) takes rvalue references, I'd have to go looking for the 
existence of another function. This is one of those cases where 
it's hard to prove a negative, as other functions can be 
introduced by mixins. This is a strong usability negative.


Next, the @disable applies to the entire parameter list. 
However, overload selection is done by looking at each 
parameter. The DIP says:


"The DIP author responded that ideas to improve this are 
welcome, but that he cannot imagine a use case."


I can guarantee that the use case of more than one reference 
parameter will come up. The workarounds the DIP suggests are 
simply awful.


Let's look at what C++ does for rvalue references:


http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html


The syntax is attached to the parameter declaration of the 
function it applies to, not some other function, and not every 
parameter:


int foo(T&& t);  // C++ rvalue ref

There are no weird workarounds, at least for that aspect. There 
are indeed unlikable things about the C++ rules, but the DIP 
needs to pay more attention to how C++ does this, and justify 
why D differs. Particularly because D will likely have to have 
some mechanism of ABI compatibility with C++ functions that 
take rvalue references.


This is not a small problem.

A further problem is implicit conversions, which the DIP 
ignores by only talking about ints.


void bar(int);
void foo(ref int);
enum short s = 10;
bar(s); // compiles
foo(s); // currently fails to compile

Should `s` be promoted to an int temporary, then pass the 
temporary by reference? I can find no guidance in the DIP. What 
if `s` is a uint (i.e. the implicit conversion is a type paint 
and involves no temporary)?


Here's a discussion of Rust and rvalue references which may 
offer insight:


https://www.reddit.com/r/rust/comments/3ko5pm/explaining_cs_rvalue_references_from_a_rust/



That the DIP applies to statements, not expressions.


The DIP should not invent its own syntax, give no explanation 
of it, and have the reader guess. (It did explain the :=, but 
not the use of { } and statements.) And, even if one did a 
mental rewrite, the semantics of the statement version are 
simply wrong. (For example, if 'fun' was actually a function 
pointer returned by another function, and that other function 
threw an exception - then the destructor would be run on an 
uninitialized variable.)



That the construction order issue is trivially fixable, by 
specifying the same behaviour as the non ref case modulo ref.


It should never have gotten this far without giving a precise 
explanation of how exception safety is achieved when faced with 
multiple parameters. In the past I've done a lot of work on 
exception safety, and it isn't trivial once one goes beyond 
trivial cases.


All that criticism aside, I'd like to see rvalue references in 
D. But the DIP needs significant work.


For future reference, this is what a formal review should be. I'd 
also rather your exact words than some summarization of them.


Re: DIP 1016--ref T accepts r-values--Formal Assessment

2019-01-24 Thread Rubn via Digitalmars-d-announce

On Thursday, 24 January 2019 at 23:18:11 UTC, kinke wrote:

Proposed `out` semantics:
---
void increment(out long value) { ++value; }
increment(out value);
---

vs. pointer version with current `out` semantics:
---
void increment(long* pValue) { ++(*pValue); }
increment();
---

The pointer workaround is both ugly (C) and unsafe (you can 
pass null).


@safe void safestFunction() {
int* ptr;
increment(out *ptr); // can also pass null to ref/out even in 
@safe

}

It's probably going to be a hard sell to change the behavior of 
out now as well. It'd break quite a bit of code I think, did a 
search through druntime and phobos and quite a few functions use 
it. Maybe user code uses it less, I know I never use it.


Re: DIP 1016--ref T accepts r-values--Formal Assessment

2019-01-24 Thread Rubn via Digitalmars-d-announce

On Thursday, 24 January 2019 at 20:01:45 UTC, kinke wrote:

On Thursday, 24 January 2019 at 09:49:14 UTC, Manu wrote:
We discussed and concluded that one mechanism to mitigate this 
issue
was already readily available, and it's just that 'out' gains 
a much
greater sense of identity (which is actually a positive 
side-effect if

you ask me!).
You have a stronger motivation to use 'out' appropriately, 
because it

can issue compile errors if you accidentally supply an rvalue.


`out` with current semantics cannot be used as drop-in 
replacement for shared in-/output ref params, as `out` params 
are default-initialized on entry. Ignoring backwards 
compatibility for a second, I think getting rid of that would 
actually be beneficial (most args are probably already 
default-initialized by the callee in the line above the 
call...) - and I'd prefer an explicitly required `out` at the 
call site (C# style), to make the side effect clearly visible.


I'd have otherwise proposed a `@noRVal` param UDA, but 
redefining `out` is too tempting indeed. ;)


Yah I'd like this approach way better and it could be an error if 
the function didn't assign the variable a value instead. Rather 
than just default initializing it.


void test(out int value) {
// error: value must be assigned a value
}

In the event the value passed isn't initialized. Can be dangerous 
if it is a struct with a destructor though. If they void 
initialized it, but I guess that's a problem with the current 
implementation as well.


Re: DIP 1016--ref T accepts r-values--Formal Assessment

2019-01-24 Thread Rubn via Digitalmars-d-announce
On Thursday, 24 January 2019 at 09:24:19 UTC, Nicholas Wilson 
wrote:

On Thursday, 24 January 2019 at 07:18:58 UTC, Mike Parker wrote:
Walter and Andrei have declined to accept DIP 1016, "ref T 
accepts r-values", on the grounds that it has two fundamental 
flaws that would open holes in the language. They are not 
opposed to the feature in principle and suggested that a 
proposal that closes those holes and covers all the bases will 
have a higher chance of getting accepted.


You can read a summary of the Formal Assessment at the bottom 
of the document:


https://github.com/dlang/DIPs/blob/master/DIPs/rejected/DIP1016.md



void atomicIncrement(ref shared long x);
atomicIncrement(myInt);


Raises a good point, not covered by @disable where the intent 
is to modify it and modifying a temporary is wrong. `out ref` 
perhaps?


Why isn't it covered by @disable ?


Re: DConf 2019: Shepherd's Pie Edition

2018-12-23 Thread Rubn via Digitalmars-d-announce

On Sunday, 23 December 2018 at 10:07:40 UTC, Walter Bright wrote:
BTW, another point for the presentations is that we cover the 
air fare and hotel expenses for the presenters. Quite a lot of 
people have been able to attend because of this. It's our way 
of giving a little bit back to strong contributors.



I'll take that to assume you aren't paying for your own ticket, 
your own hotel expenses, etc. I wonder if you would feel 
differently about this if you had to pay for all these out of 
your own pocket. I'd be curious of the total expenses for DConf, 
all of the funds could be used to hire more developers. The pull 
request situation has improves significantly, I can only imagine 
what else could improve with those additional funds. I think it'd 
fair to outline how much does end up being spent on DConf and do 
a logical comparison of money being spent relatively. I know how 
you feel about owing people of the your community nothing though, 
so I guess it's a nice dream. Without those statistics to include 
with the argument it's pointless to argue with you, might as well 
be arguing whether unicorns exist.


Re: Blog post: What D got wrong

2018-12-19 Thread Rubn via Digitalmars-d-announce
On Wednesday, 19 December 2018 at 19:58:53 UTC, Neia Neutuladh 
wrote:

On Wed, 19 Dec 2018 17:28:01 +, Vijay Nayar wrote:
Could you please elaborate a little bit more on this?  In the 
linked program, I had expected that "ref" would return a 
reference to "a" that would behave similar to a pointer.


They work like pointers that automatically dereference when 
assigning to the base type.


Only three things in D can be ref:
* A function parameter
* A function return value
* A foreach variable (since that's either going to be a 
function return
value, a function parameter, or a pointer, depending on what 
you're

iterating over)

So when the compiler sees something like:

ref int foo();
auto a = foo();

It sees that the type of 'a' has to be the same as the return 
type of 'foo'. Except that's not possible, so it uses the 
nearest equivalent type: int.


And if you have:

ref int foo();
int a = foo();

That obviously converts by copying the value.


To be fair even in c++ this won't be a reference.

int& foo();
auto a = foo(); // a == int
auto& a = foo(); // a == int&

So it shouldn't be that surprising.


Re: DIP 1015--Deprecation of Implicit Conversion of Int. & Char. Literals to bool--Formal Assement

2018-11-14 Thread Rubn via Digitalmars-d-announce
On Wednesday, 14 November 2018 at 02:45:38 UTC, Walter Bright 
wrote:

On 11/13/2018 3:29 PM, Rubn wrote:
> enum A : int { a = 127 }

`a` is a manifest constant of type `A` with a value of `127`.

Remember that `A` is not an `int`. It is implicitly convertible 
to an integer type that its value will fit in (Value Range 
Propagation). Other languages do not have VRP, so expectations 
from how those languages behave do not apply to D. VRP is a 
nice feature, it is why:


enum s = 100; // typed as int
enum t = 300; // also typed as int
ubyte u = s + 50; // works, no cast required,
  // although the type is implicitly 
converted

ubyte v = t + 50; // fails

In your articles, it is crucial to understand the difference 
between a manifest constant of type `int` and one of type `A`.


At least can you understand where the problem lies? If you have 
code like this:


foo(Enum.value);

Then it gets changed:

// ops might be calling a different function now
foo(runtimeCond ? Enum.value : Enum.otherValue);

Or how about if we just add another enum to our list:

enum Enum : int {
// ...
// add new enum here, shifting the values down
value,  // 126 -> 127
otherValue, // 127 -> 128 - Ops now we are calling a 
different function ~somewhere~

// ...
}

From your implementation perspective I can see why it is a good 
thing. But from my user's perspective this just screams 
unreliable chaotic mess, even in the most trivial examples.


What D does is only suitable for the absolute most trivial 
example:


enum int s = 100;
ubyte v = s; // ok no cast required

But even just a slightly more trivial example like we have now, 
and it falls apart:


enum int s = 100;

void foo(int);
void foo(byte);

foo(s); // Not suitable for determining overloads
// though is good for variable initialization

Not one's really asking to add another layer to anything. Merely 
to not treat named enum types as if they are just constants like 
anonymous enums.


ubyte a = Enum.value; // this is ok
foo(Enum.value);  // this needs to be x1000 more reliable



Re: DIP 1015--Deprecation of Implicit Conversion of Int. & Char. Literals to bool--Formal Assement

2018-11-13 Thread Rubn via Digitalmars-d-announce

On Monday, 12 November 2018 at 22:07:39 UTC, Walter Bright wrote:
One could have  be treated as 
"better than" , and 
it sounds like a good idea, but even C++, not known for 
simplicity, tried that and had to abandon it as nobody could 
figure it out once the code examples got beyond trivial 
examples.


I wonder what these examples are? What did C++ do instead, cause 
something tells me it didn't do what D is doing. An enum in C++ 
doesn't call different function overloads based on the constant 
value.


The trivial examples with D's current implementation aren't even 
understood by most people it seems like.





Re: DIP 1015--Deprecation of Implicit Conversion of Int. & Char. Literals to bool--Formal Assement

2018-11-13 Thread Rubn via Digitalmars-d-announce

On Monday, 12 November 2018 at 22:07:39 UTC, Walter Bright wrote:

On 11/12/2018 12:34 PM, Neia Neutuladh wrote:

Tell me more about this "consistency".


int f(short s) { return 1; }
int f(int i) { return 2; }

enum : int { a = 0 }
enum A : int { a = 0 }

pragma (msg, f(a));   // calls f(int)
pragma (msg, f(A.a)); // calls f(short)

I.e. it's consistent.

Here's how it works:

f(a): `a` is a manifest constant of type `int`, and `int` is an 
exact match for f(int), and f(short) requires an implicit 
conversion. The exact match of f(int) is better.


f(A.a): `a` is an enum of type `A`. `A` gets implicitly 
converted to `int`. The `int` then gets exact match to f(int), 
and an implicit match to f(short). The sequence of conversions 
is folded into one according to:


=> conversion>
  => conversion>


Both f(int) and f(short) match, because implicit conversions 
rank the same. To disambiguate, f(short) is pitted against 
f(int) using partial ordering rules,

which are:

Can a short be used to call f(int)? Yes.
Can an int be used to call f(short)? No.

So f(short) is selected, because the "Most Specialized" 
function is selected when there is an ambiguous match.


Note: the "most specialized" partial ordering rules are 
independent of the arguments being passed.


---

One could have  be treated as 
"better than" , and 
it sounds like a good idea, but even C++, not known for 
simplicity, tried that and had to abandon it as nobody could 
figure it out once the code examples got beyond trivial 
examples.


This just seems like a bug to me. Any sane human being would 
expect all these functions to output the same thing. But it 
entirely depends on how you use it.


import std.stdio;

void foo(byte v) { writeln("byte ", v); }
void foo(int v) { writeln("int ", v); }

enum : int { a = 127 }
enum A : int { a = 127 }

void main()
{
A v = A.a;
foo(A.a); // byte 127 < These two are probably the best 
showcase of what's wrong
foo(v);   // int 127  < same values being passed with same 
type but different result


foo(a);   // int 127
foo(127); // int 127
}

https://run.dlang.io/is/aARCDo



Re: Funding for code-d/serve-d

2018-05-05 Thread Rubn via Digitalmars-d-announce

On Saturday, 5 May 2018 at 11:21:29 UTC, Mike Parker wrote:
This morning at the Hackathon I announced that the D Foundation 
is raising money for code-d/serve-d, the plugin for Visual 
Studio Code and its companion Microsoft Language Server 
Protocol implementation for D.


We've set up a goal of $3000 at our Open Collective page:

https://opencollective.com/dlang#

At the top of the page, you'll see our current balance, the 
projected balance at the end of the year based on the current 
level of monthly donations, and the goal of $3000 on the far 
right.


We're sitting at just over $1100 as I write this, which means 
we're almost halfway there already. We encourage those of you 
who use Webfreak's VS Code plugin to contribute whatever you 
can in order to fund its development, especially if you want to 
see it improve.


An important point is that development on serve-d can 
ultimately benefit not just code-d, but other IDE and editor 
plugins where it may be used.


If we reach $2700 within 30 days, the D Foundation will throw 
in the remaining $300 and we'll let Webfreak get to work.


If this proves successful, we hope to use future goals to fund 
development across the D ecosystem. Some of our targets will be 
driven by the results of the recent State of D Survey and 
others will be driven by other concerns. If you are interested 
in helping to move the state of D development forward, please 
consider contributing!


Any roadmap for what improvements will be made? It seems like it 
might have been a better choice to support dcd/dscanner/dfix. 
Most of the functionality is provided by those utilities for 
pretty much every IDE toolset out there, including code-d/serve-d.


Re: User Stories: Funkwerk

2018-03-16 Thread Rubn via Digitalmars-d-announce

On Wednesday, 14 March 2018 at 14:17:50 UTC, Mike Parker wrote:

foreach(auto element: elements)


":" is C++ syntax




Re: Beta 2.079.0

2018-02-22 Thread Rubn via Digitalmars-d-announce

On Friday, 23 February 2018 at 00:05:59 UTC, Martin Nowak wrote:

- each imported module should be on it's own line

  That's your opinion, my opinion is that importing 6 symbols 
from 6 different modules for a tiny cli tool sucks and bloats 
code example. So the alternative is to not use selective 
imports, but only those and static imports have a clear path to 
become lazy (https://issues.dlang.org/show_bug.cgi?id=13255).


This can be solved by adding a package.d to phobos. This doesn't 
need a language change that introduces more ambiguities for such 
a subjective matter as "I'm too lazy to write 5 more lines of 
code". 5 Lines of code is hardly bloat for a code example. 
Example code is better to follow best practices, or you get the 
whole `using namespace std` situation like you do with C++. The 
people that actually can comprehend won't be hindered by it, and 
everyone else it won't make a difference cause they have no 
understanding of what they are doing and just copy and paste the 
code.