August 28, 2018
On Tuesday, 28 August 2018 at 08:44:26 UTC, Chris wrote:
>
> When people choose a programming language, there are several boxes that have to be ticked, like for example:
>
> - what's the future of language X? (guarantees, stability)
> - how easy is it to get going (from "Hello world" to a complete tool chain)
> - will it run on ARM?
> - will it be a good choice for the Web (e.g. webasm)?
> - how good is it at data processing / number grinding
> - etc.
>

I don't know if all their claims are 100% true, but let that sink in for a while:

https://julialang.org/.


August 28, 2018
On 8/27/2018 7:02 AM, Don wrote:
> I can explain this, since I did the original implementation.
> [...]
Thank you, Don. And you do have my mad respect for figuring out Windows SEH.
August 28, 2018
On Tuesday, 28 August 2018 at 08:44:26 UTC, Chris wrote:

>
> Last but not least, if it's true that the D Foundation has raised only 3.2K, then there's something seriously wrong.

The Foundation has significantly more than 3.2k. The Open Collective account is relatively new and is but one option. People also donate via PayPal and other means [1], with several monthly contributors. The Foundation is paying two full-time developers, pays me for part-time work, pays out bounties for guest posts on the D Blog, pays out bounties for specific coding tasks, contributes to the funding of DConf, and more.

Soon there will be more fundraising drives for targeted initiatives, like the test drive we did with the VS Code plugin, to make up for the lack of donations of time. Some of them will be for paying people to fix onerous issues in Bugzilla. It's a long-term project for me.

[1] https://dlang.org/foundation/donate.html
August 28, 2018
On Thursday, 23 August 2018 at 09:29:30 UTC, Nicholas Wilson wrote:
> On Thursday, 23 August 2018 at 07:00:01 UTC, Iain Buclaw wrote:
>> On Thursday, 23 August 2018 at 06:34:04 UTC, Shachar Shemesh wrote:
>>> On 23/08/18 09:17, Jacob Carlborg wrote:
>>>> I don't see why we just can't add support for scoped lazy parameters. It's already in the language just with a different syntax (delegates). That would probably be an easy fix (last famous words :)). I guess it would be better if it could be inferred.
>>>
>>> Here's the interesting question, though: is this *going* to happen?
>>>
>>> We've known about this problem for ages now. No movement.
>>>
>> It's on my todo list, however I've instead been doomed to work on higher priority things.
>>
>> More generally though, some time should be spent on trying out things in the spirit of "will it blend" just to see what happens.
>>  Putting effort towards having a more homogeneous environment in the language should in the long run pay its dividends.
>
> Is there even any way to escape a lazy? If no, then lazy is identical to scope lazy.
> E.g. https://run.dlang.io/is fails to compile

Link not found. I assume you tried something like returning a delegate that references a lazy parameter?
August 28, 2018
On Thursday, 23 August 2018 at 15:35:45 UTC, Joakim wrote:
> On Thursday, 23 August 2018 at 07:37:07 UTC, Iain Buclaw wrote:
>> On Thursday, 23 August 2018 at 06:58:13 UTC, Joakim wrote:
>>> On Thursday, 23 August 2018 at 03:50:44 UTC, Shachar Shemesh wrote:
>>>> [...]
>>>
>>> Can you list what you or other Weka devs believe those fatal flaws to be? Because you've not listed any here, which makes you no better than some noob that comes in here, says D has to get better or it will die, then can't articulate what they mean by "better" or worse, mentions something trivial. Of course, you've actually used the language for years, so presumably you've got some real concerns, but do you really think the bug you just posted is "fatal" to the language?
>>>
>>> If you think there are fatal flaws, you might as well list them, whether technical or the development process, or you will just be ignored like any other noob who talks big and can't back it up. You may be ignored anyway, ;) but at least you'll have made a case that shows you know what you're talking about.
>>
>> I'd define fatal as some that can be fixed, but breaks 100% of everyone's code, even if the change is net positive all round.
>>
>> However how big a problem really is is in the eye of the beholder. An example:
>>
>> Symptom: The compiler can't discard unused symbols at compile time, and so it will spend a lot of time pointlessly optimising code.
>>
>> Problem: D has no notion of symbol visibility.
>>
>> Possible Solution: Make all globals hidden by default unless 'export'.
>>
>> Side effects: Everyone will be spending weeks to months fixing their libraries in order to only mark what should be visible outside the current compilation unit as 'export'.
>>
>> Benefits: Faster compile times, as in, in the most extreme example I've built one project on github with gdc -O2 and build time went from 120 seconds to just 3!
>
> So your example of a fatal flaw is that D could be 100X faster at compilation instead of just 10X than most every other native language out there?! C'mon.
>

But that's not true. D isn't a fast language to compile, dmd is just a fast compiler.

You may get a little leading edge with codebases that are effectively C. Once you throw templates into the mix though, your problems become exponential.

Spending 4 seconds in the front end and codegen, only to wait 2 minutes in the optimizer is horrific.

The alternative of discarding what seem to be unused symbols only results in linker error of the obscure edge cases sort.

Template emission strategy is a mess, we're better off just instantiating all templates in all compilation units, and let the compiler decide whatever to discard. Even -allinst does not instantiate enough to allow the compiler to make such decisions that C++ has no problem with (most of the time).
August 28, 2018
On Mon, Aug 27, 2018 at 06:11:14PM -0700, Walter Bright via Digitalmars-d wrote:
> On 8/27/2018 10:08 AM, H. S. Teoh wrote:
> > Const in D makes sense as-is.  Though, granted, its infectiousness means
> > its scope is actually very narrow, and as a result, we ironically
> > can't use it in very many places, and so its touted benefits only
> > rarely apply. :-(  Which also means that it's taking up a lot of
> > language design real estate with not many benefits to show for it.
> 
> D const is of great utility if you're interested in functional programming.  Using it has forced me to rethink how I separate tasks into functions, and the result is for the better.
> 
> I agree that D const has little utility if you try to program in C++ style.

I am very interested in functional programming, yet ironically, one of D's top functional programming selling points, ranged-based programming, interacts badly with const.  Just ask Jonathan about using ranges with const, and you'll see what I mean. :-)

The very design of ranges in D requires that the range be mutable. However, because const is infectious, this makes it a royal pain to use in practice.  Take, for example, a user-defined container type, let's call it L. For argument's sake, let's say it's a linked list.  And let's say the list elements are reference-counted -- we'll write that as RefCounted!Elem even though this argument isn't specific to the current Phobos implementation of RefCounted.

As experience has shown in the past, it's usually a good idea to separate the container from the range that iterates over it, so an obvious API choice would be to define, say, an .opSlice method for L that returns a range over its elements.

Now, logically speaking, iterating over L shouldn't modify it, so it would make sense that .opSlice should be const. So we have:

	struct L {
		private RefCounted!Elem head, tail;
		auto opSlice() const {
			...
		}
	}

The returned range, however, must be mutable, since otherwise you couldn't use .popFront to iterate over it (and correspondingly, Phobos isInputRange would evaluate to false).  But here's the problem: because opSlice is declared const, that means `this` is also const, which means this.head and this.tail are also const.  But since this.head is const, that means you couldn't do this:

	auto opSlice() const {
		struct Result {
			RefCounted!(const(Elem)) current;
			... // rest of range API
			void popFront() {
				current = current.next;
				// Error: cannot assign const(RefCounted!Elem) to RefCounted!(const(Elem))
			}
		}
		return Result(head); // <-- Error: cannot assign const(RefCounted!Elem) to RefCounted!(const(Elem))
	}

This would have worked had we used pointers instead, because the
compiler knows that it's OK to assign const(Elem*) to const(Elem)*.
However, in this case, the compiler has no way of knowing that it is
safe to assign const(RefCounted!Elem) to RefCounted!(const(Elem)).
Indeed, they are different types, and the language currently has no way
of declaring the head-mutable construct required here.

This is only the tip of the iceberg, of course.  If you then try to add a method to RefCounted to make it convert const(RefCounted!T) to RefCounted!(const(T)), then you'll be led down a rabbit hole of further problems with const (e.g., how to implement ref-counting with const objects in a way that doesn't violate the type system) until you reach the point where it's impossible to proceed without casting away const somehow.  Unfortunately, the spec says that's Undefined Behaviour.  So you're on your own.

This is just one example among many, that const is hard to use in the general case.  It works fairly well for a narrow number of cases, such as for built-in types, but once you start generalizing your code, you'll find brick walls in undesired places, the workarounds for which require so much effort as to offset any benefits that const may have brought.

TL;DR: const is beautiful in theory, but hard to use in practice.  So hard that it's often not worth the trouble, despite the benefits that it undoubtedly does provide.

P.S. If D had the concept of head-mutable, a lot of this pain (though not all) would have been alleviated.


T

-- 
"I'm running Windows '98." "Yes." "My computer isn't working now." "Yes, you already said that." -- User-Friendly
August 28, 2018
On Tue, Aug 28, 2018 at 08:18:57AM +0000, Eugene Wissner via Digitalmars-d wrote: [...]
> There are still valid use cases where const should be "broken". One of them is mutex (another one caching). I have very little experiance in multi-threaded programming, but what do you think about "mutable" members, despite the object is const?

The problem with compromising const is that it would invalidate any guarantees const may have provided.  Const in D is not the same as const in languages like C++; const in D means *physical* const, as in, the data might reside in ROM where it's physically impossible to modify. Allowing the user to bypass this means UB if the data exists in ROM.

Plus, the whole point of const in D is that it is machine-verifiable, i.e., the compiler checks that the code does not break const in any way and therefore you are guaranteed (barring compiler bugs) that the data does not change.  If const were not machine-verifiable, it would be nothing more than programming by convention, since it would guarantee nothing.  Allowing const to be "broken" somewhere would mean it's no longer machine-verifiable (you need a human to verify whether the semantics are still correct).

Many of D's const woes can actually be solved if we had a language-supported way of declaring the equivalence between const(U!T) and U!(const(T)), AKA head-mutable.  The language already supports a (very) limited set of such conversions, e.g., const(T*) is assignable to const(T)*, because you're just making a copy of the pointer, but the target is still unchangeable.  However, because there is no way to specify such a conversion in a user-defined type, that means things like RefCounted, or caches, or mutexes, cannot be made to work without either ugly workarounds or treading into UB territory by casting away const.

But if there is a way for a user-defined template U to define a
conversion from const(U!T) to U!(const(T)) (the conversion code, of
course, would have to be const-correct and verifiable by the compiler),
then we could make it so that U!(const(T)) contained a mutable portion
(e.g., the refcount, mutex, cache, etc.) and an immutable portion (the
reference to the const object).


T

-- 
In order to understand recursion you must first understand recursion.
August 28, 2018
On Tuesday, 28 August 2018 at 13:39:40 UTC, Iain Buclaw wrote:
> On Thursday, 23 August 2018 at 15:35:45 UTC, Joakim wrote:
>> On Thursday, 23 August 2018 at 07:37:07 UTC, Iain Buclaw wrote:
>>> On Thursday, 23 August 2018 at 06:58:13 UTC, Joakim wrote:
>>>> On Thursday, 23 August 2018 at 03:50:44 UTC, Shachar Shemesh wrote:
>>>>> [...]
>>>>
>>>> Can you list what you or other Weka devs believe those fatal flaws to be? Because you've not listed any here, which makes you no better than some noob that comes in here, says D has to get better or it will die, then can't articulate what they mean by "better" or worse, mentions something trivial. Of course, you've actually used the language for years, so presumably you've got some real concerns, but do you really think the bug you just posted is "fatal" to the language?
>>>>
>>>> If you think there are fatal flaws, you might as well list them, whether technical or the development process, or you will just be ignored like any other noob who talks big and can't back it up. You may be ignored anyway, ;) but at least you'll have made a case that shows you know what you're talking about.
>>>
>>> I'd define fatal as some that can be fixed, but breaks 100% of everyone's code, even if the change is net positive all round.
>>>
>>> However how big a problem really is is in the eye of the beholder. An example:
>>>
>>> Symptom: The compiler can't discard unused symbols at compile time, and so it will spend a lot of time pointlessly optimising code.
>>>
>>> Problem: D has no notion of symbol visibility.
>>>
>>> Possible Solution: Make all globals hidden by default unless 'export'.
>>>
>>> Side effects: Everyone will be spending weeks to months fixing their libraries in order to only mark what should be visible outside the current compilation unit as 'export'.
>>>
>>> Benefits: Faster compile times, as in, in the most extreme example I've built one project on github with gdc -O2 and build time went from 120 seconds to just 3!
>>
>> So your example of a fatal flaw is that D could be 100X faster at compilation instead of just 10X than most every other native language out there?! C'mon.
>>
>
> But that's not true. D isn't a fast language to compile, dmd is just a fast compiler.
>
> You may get a little leading edge with codebases that are effectively C. Once you throw templates into the mix though, your problems become exponential.
>
> Spending 4 seconds in the front end and codegen, only to wait 2 minutes in the optimizer is horrific.
>
> The alternative of discarding what seem to be unused symbols only results in linker error of the obscure edge cases sort.
>
> Template emission strategy is a mess, we're better off just instantiating all templates in all compilation units, and let the compiler decide whatever to discard. Even -allinst does not instantiate enough to allow the compiler to make such decisions that C++ has no problem with (most of the time).

I think I've hit a variation of this problem before, where pulling in a single selective import in Phobos somewhere meant the entire module was compiled into the executable (though I suppose that could be a linker issue?):

https://forum.dlang.org/thread/gmjqfjoemwtvgqrtdsdr@forum.dlang.org

I guess this is why scoped/selective imports didn't help that much in disentangling Phobos. I figured it wasn't a big deal if it was just causing bigger executables, but even though I mentioned compilation speed there, I didn't think of how that's slowing down the compiler too, as you now note.

Pruning what's evaluated by the compiler based on scoped/selective imports, rather than apparently including the whole module, and getting D compilers to compile parallelized without separately invoking each module/package, ie a -j flag for the compiler when you invoke it with all your source at once, might be good projects for us to crowdfund, as discussed in this and my earlier Nim thread. Separate parallel compilation works wonders on my octa-core Android/AArch64 phone, where I mostly build D now, would be good to be able to combine that with invoking ldc with all source at once.
August 28, 2018
On Tue, 28 Aug 2018 at 00:55, Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 8/26/2018 11:16 PM, Manu wrote:
> >> The code looks the same, and in fact, is about 98% the same.
> > This code appears to be a mechanical translation.
>
> It's not. It's by hand. But I had a specific goal of minimizing the diffs, so that if the translation didn't work, it reduced the number of places to look for the mistake. And in fact, this has saved me a LOT of grief :-)
>
>
> > That's not what
> > happened in this case; he wrote his game in D from scratch.
> > It was just that he arrived at mostly the same place. He was googling
> > for styling and sample material, but I suspect the problem was a lack
> > of topical material demonstrating how he might write his D code
> > differently.
>
> It takes time to learn how to write idiomatic D effectively. I'm still learning how to do it right, too.
>
>
> > It's also the case that the significant difference between C++ and D
> > (in my experience) mostly come down to: D has modules, tidier meta,
> > UDA's, slices, and ranges/UFCS. In trade, D struggles with const, and
> > ref is broken.
> > If your code doesn't manifest some gravity towards one of those
> > features, it will tend to be quite same-ey, and advantage may not be
> > particularly apparent.
>
> I suspect that is still a bit stuck on looking at individual instruments and not seeing the orchestra.
>
> Let's take the much-maligned D const. It isn't C++ const (let's call that "head-const", because that's what it is). Head-const for a function parameter tells us very little about what may happen to it in the function. You can pass a head-const reference to a container, and have the function add/change/delete every element of that container, all without a peep from any C++ tool. Looking at the function signature, you've really got no clue whatsoever.
>
> The reason people have trouble with transitive-const is that they are still programming in C++, where they *do* add/change/delete every member of the "const" container.

We understand... really. I've spent a decade digesting this, and I'm not one of those that has ever really complained about D's const. I've always mostly bought into it philosophically.

The reality is though, that D's const is not actually very useful, and
C++'s const is. D has no way to express head-const, and it turns out
it's a tremendously useful concept.
As I said, I tend to create a head-const hack to use in its place, and
that gets me out of jail... but it's specified as undefined behaviour,
which isn't great.

> That includes me. I try to add transitive-const, and it won't compile, because I as well am used to replacing the engine and tail lights in my head-const car. In order to use transitive-const, it's forcing me to fundamentally re-think how I organize code into functions.

I often walk the same path, but sometimes it doesn't yield success,
and in many cases, it just doesn't actually model the problem.
If the problem is that I want a const container class; I don't want a
function I pass a vector to mutate the container structure, that is,
add/remove/reorder/reallocate the array, but I DO intend it to
interact with mutable elements.
That's a perfectly valid problem structure, and it turns out, it's
very common. I would attribute the given element type as const if I
wanted the const-ness to propagate to the elements, that's obvious and
convenient.

It might be that we can sufficiently rearrange all manner of
conventional wisdom to interact successfully with D's const, but I've
been watching this space for 10 years, and nobody has produced any
such evidence, or articles that we can read and understand how to
wrangle successful solutions.
This particular class of problem reeks of the typical criticism for
Rust... that is, I have better things to be doing with my time than
trying to find awkward alternative code structures to pacify the
const-checker, when in reality, const-container-of-mutable-elements is
simply the correct conceptual modeling of the problem.

Anyway, I'm not fighting that battle. I have enough of my own.

> For example, dmd is full of functions that combine data-gathering with taking-action. I've been reorganizing to separate data-gathering and taking-action into separate functions. The former can be transitive-const, maybe even pure. And I like the results, the code becomes much easier to understand.

I've also had occasional success refactoring to support const, but it's certainly the case that success is not guaranteed. And it's always time consuming regardless.
August 28, 2018
On Tue, Aug 28, 2018 at 10:20:06AM -0700, Manu via Digitalmars-d wrote: [...]
> The reality is though, that D's const is not actually very useful, and C++'s const is.

Actually, I think C++ const is not very useful, because it guarantees nothing. At the most, it's just a sanity checker to make sure the programmer didn't accidentally do something dumb. But given an opaque C++ function that takes const parameters, there is ZERO guarantee that it doesn't actually modify stuff behind your back, and do so legally (per spec).  I mean, how many times have you written const_cast<...> just to get a piece of code to compile?  I know I've been guilty of this in many places, because it simply isn't worth the effort to track down all the places of the code that you need to fix to make it const-correct.  So basically, C++ const is nothing more than an annotation that isn't really enforced.

But you're spot on about D's const, though.  While D's const *does* provide real guarantees (unless you tread into UB territory by casting it away), that also limits its scope so much that it's rarely useful outside of rather narrow confines.  Yet because it's so strict, using it requires investing significant effort.  So you end up with the unfortunate situation of "a lot of effort" + "limited usefulness" which for many people equals "not worth using".


> D has no way to express head-const, and it turns out it's a tremendously useful concept.

I can live without head-const... but what *really* makes const painful for me is the lack of head-mutable. I.e., given a const container (which implies const objects), there is no universal way to obtain a mutable reference to said const objects, unless you tread into UB territory by forcefully casting it away.  This makes const so limited in applicability that, for the most part, I've given up using const at all, in spite of having tried quite hard to use it as much as possible for years.


[...]
> I've also had occasional success refactoring to support const, but it's certainly the case that success is not guaranteed. And it's always time consuming regardless.

Yes, it's time-consuming.  And takes significant effort.  In spite of being rather limited in applicability.  In my experience, it's useful for isolated pieces of code near the bottom of the program's call chain, where there is little or no additional dependencies.  But it's just too cumbersome to use at any higher level, and a royal pain in generic code (which I'm quite heavy on).  It probably *can* be made to work in most cases, but it falls under my umbrella category of "too much effort needed, only marginal benefits, therefore not worth it".


T

-- 
A linguistics professor was lecturing to his class one day. "In English," he said, "A double negative forms a positive. In some languages, though, such as Russian, a double negative is still a negative. However, there is no language wherein a double positive can form a negative." A voice from the back of the room piped up, "Yeah, yeah."