December 25, 2011
Timon Gehr:

> > http://pastebin.com/C6vf9DQQ

If possible I suggest to remove all the BigInt from the module, and put the bigint import into the main():

void main() {
    import std.bigint;
    auto h = hamming!BigInt();
    writeln(take(20, h));
    writeln(h()[1_691]);
    writeln(h()[1_000_000]);
}


> @nonstrict:
> 
> r=cast(T)1
>      .cons(
>                   r.map((a)=> 2*a)
>            .merge(r.map((a)=> 3*a))
>            .merge(r.map((a)=> 5*a))
>      );

This version looks acceptable :-)

Bye,
bearophile
December 25, 2011
On 12/26/2011 12:30 AM, bearophile wrote:
> Timon Gehr:
>
>>> http://pastebin.com/C6vf9DQQ
>
> If possible I suggest to remove all the BigInt from the module, and put the bigint import into the main():
>
> void main() {
>      import std.bigint;
>      auto h = hamming!BigInt();
>      writeln(take(20, h));
>      writeln(h()[1_691]);
>      writeln(h()[1_000_000]);
> }
>

That could be done, but I don't think it is terribly important.

>
>> @nonstrict:
>>
>> r=cast(T)1
>>       .cons(
>>                    r.map((a)=>  2*a)
>>             .merge(r.map((a)=>  3*a))
>>             .merge(r.map((a)=>  5*a))
>>       );
>
> This version looks acceptable :-)
>
> Bye,
> bearophile

It would be even better with methods-as-operators:

r=cast(T)1 cons (( r map a=>2*a ) merge ( r map a=>3*a ) merge ( r map a=>5*a ))












December 26, 2011
On 12/25/11 5:13 PM, Adam D. Ruppe wrote:
> On Sunday, 25 December 2011 at 04:44:57 UTC, Andrei Alexandrescu wrote:
>> I see every letter beyond this as a liability:
>
> Yeah, though like Jacob said, the implementation doesn't
> matter as much as the idea of giving it a name.
>
> But, if you're curious about why I wrote it long form, it's
> just a quirk I sometimes do; if I read something out loud
> differently than how I wrote it, I'll sometimes rewrite it.
> Here, I dictated it to myself as "if it's divisible by two,
> return false (not odd), otherwise, return true (is odd)", and
> decided to write it almost exactly like that.

I understand. Personally, I am unable to bring myself to fathom why writing this has any advantage:

if (condition)
    return true; // or false
else
    return false; // or true, respectively

as much as I'm unable to fathom why writing this has any advantage:

if (expression == true) ...

or

if (expression == false) ...

I might be biased, but I ask for it to be corrected if I see it during a code review at work, and if someones writes such during an interview, it doesn't gain them any points.

> Usually, these little things are meaningless once compiled,
> but check this out:
[snip]

I'd say that's a good enhancement request for the backend.


Andrei
December 26, 2011
On Saturday, December 24, 2011 21:37:12 Kapps wrote:
> The two biggest things that I believe D would benefit from, in terms of readability, are UFCS and C#-style lambdas (which were already discussed).
> 
> Something like
> 'array(find("test", select!("a.name")(filter!("a.num > 3")(Elements))))'
> Could be rewritten much cleaner as
> Elements.filter!"a.num > 3"
> .select!"a.name"
> .find("test")
> .array();
> 
> The first one is very confusing, hard to split across multiple lines without losing meaning, and difficult to see what it even operates on (assume Elements is not an array and thus can not be used with the current implementation of UFCS). The second one, you can clearly see operates on Elements, you can clearly split it across multiple lines, and it's very obvious where things stop and end. Plus, it eliminates at least one set of parenthesis per function call, not to mention being much easier to write as it's in order of steps instead of opposite order.

I think that that's partially a function of how much programming you've done in functional languages. I personally find the first one to be far more readable. The second one seems horribly backwards.

- Jonathan M Davis
December 26, 2011
On Monday, 26 December 2011 at 00:40:47 UTC, Andrei Alexandrescu wrote:
> I understand. Personally, I am unable to bring myself to fathom why writing this has any advantage:

if(condition) return false just avoids a negation in the
condition.

It's easier to miss a "!" entirely than to miss a "return false",
and personally, I've been finding it takes an extra brain cycle
to invert a condition anyway.

I like an individual line of code to be dumb as a rock anyway.

December 26, 2011
On Monday, 26 December 2011 at 02:31:52 UTC, Adam D. Ruppe wrote:
> I like an individual line of code to be dumb as a rock anyway.

I'm reminded of a discussion I had on another forum, where someone
suggested this might be because I started with assembly language.

It might be that those first few years shape your brain and old
habits die hard.


December 26, 2011
Le 25/12/2011 05:27, Andrei Alexandrescu a écrit :
> Got the GC book this morning, already read 2.5 chapters :o).
>
>
> Andrei
>

You'll find that you can do a lot when GC is aware of immutability (in functionnal languages, most things tends to be immutable).

In the actual state of druntime, the GC is bad, but worse, cannot be imporoved to take advantage of this, and never will unless a major changement is done in GC interface.
December 26, 2011
On 12/25/11 8:56 PM, deadalnix wrote:
> Le 25/12/2011 05:27, Andrei Alexandrescu a écrit :
>> Got the GC book this morning, already read 2.5 chapters :o).
>>
>>
>> Andrei
>>
>
> You'll find that you can do a lot when GC is aware of immutability (in
> functionnal languages, most things tends to be immutable).
>
> In the actual state of druntime, the GC is bad, but worse, cannot be
> imporoved to take advantage of this, and never will unless a major
> changement is done in GC interface.

What changes do you have in mind?

I've gone through a larger portion of the book and one thing has become very clear to me: we must improve the precision of the collector. This would be a gating feature towards taking the GC pretty much anywhere.

As a first step, we must make all allocations except stack type-aware, and leave only the stack to be imprecise.

A tactical detail of the above has become equally clear to me - we MUST use D's reflection and introspection capabilities in increasing the precision of the collector.

It's fairly easy to write a generic function mark() (as in the "mark" stage of the mark/sweep collector) that accepts any object type with indirections (class, array, associative array, pointer to struct). The function marks the pointer and then iterates through all fields of the object and recurses to itself to mark other reference/pointer/etc fields of the object.

This one generic function obviates a lot of the code necessary today for conservatively marking pointers, and also reduces and simplifies enormously the new code that would otherwise be needed in order to define precise collection.

Pointers to instances of that generic functions would be accessible from each allocated block; to transitively mark the block, the function is called via pointer.

Essentially instances of that function (which I estimate to a 50-liner) would take care of mark() for the entire universe of D types - a humongous success of compile-time reflection.


Andrei
December 26, 2011
On 24.12.2011 16:33, Andrei Alexandrescu wrote:
> On 12/24/2011 09:11 AM, Derek wrote:
>> On Sat, 24 Dec 2011 23:42:41 +1100, bearophile
>> <bearophileHUGS@lycos.com> wrote:
>>> In theory functional-style is a good to shrink the code, but in D
>>> functional-style code is a jungle of (({}){()}) so it's hard to write
>>> and hard to read.
>
> As I mentioned once, the proposition of writing functional code in D is
> quite a bit different from other languages. In languages dedicated to
> pure or almost pure functional semantics, there may literally be no
> other way to achieve anything except in functional style; if there is,
> the style is almost invariably stilted.
>
> In D, functional style code must compete with a well honed imperative
> paradigm. And as unpleasant as that may be, sometimes code that uses
> mutation may be "better" than functional code by some metrics.
>
>> I once, long ago, suggested to Walter/Andrei that D is approaching the
>> ASCII equivalent of APL. The actual text of D source code can be a
>> hindrance to reading the code, let alone understanding what has been
>> written. I know it is hyperbole, but some D source modules are close to
>> write-only code, meaning that it takes specialist/expert D knowledge to
>> understand some source code. I'm not so certain that this is a desirable
>> feature of any programming language.
>
> We recently discussed this a bit in connection with the standard
> library. It definitely could be written in a manner that is easier to
> understand for the more casual reader, but that would mean reducing the
> capabilities (e.g. no reduce with multiple parameters) and making it
> slower.
>
> That being said, I personally find contemporary application D code very
> readable. It's a pleasure to get to it after using C++ at work.
>
> Anyhow, is there anything you have in mind that we have the chance of
> improving at this point?

Improved syntax for compile-time reflection. is() expressions, especially is(typeof()), and __traits, are the least readable parts of the language. They inevitably lead to a mass of braces and parentheses.




December 26, 2011
On 2011-12-26 03:31, Adam D. Ruppe wrote:
> On Monday, 26 December 2011 at 00:40:47 UTC, Andrei Alexandrescu wrote:
>> I understand. Personally, I am unable to bring myself to fathom why
>> writing this has any advantage:
>
> if(condition) return false just avoids a negation in the
> condition.
>
> It's easier to miss a "!" entirely than to miss a "return false",
> and personally, I've been finding it takes an extra brain cycle
> to invert a condition anyway.
>
> I like an individual line of code to be dumb as a rock anyway.

It's like when you see code like this (Ruby):

unless !foo

end

Double negation. Code like the snippet above can be really annoying.

-- 
/Jacob Carlborg