December 24, 2011
Andrei Alexandrescu:

> I've never gotten why you wouldn't define amap and afilter for your own code, thus avoiding parentheses.

In D1 I did write a non-standard library to be used with Phobos. In D2 I'd like to avoid writing a dlibs2 that is used only by me. There are some functions that are probably useful for lot of people.

Bye,
bearophile
December 24, 2011
On Saturday, 24 December 2011 at 23:12:27 UTC, bearophile wrote:
> I was talking about the abundance of (({}){()}) and not about identifiers length.

It's the same fallacy. I can't read Carmack's mind, but
I'm sure he's talking about shortening code the same way
I would mean it if I said it - simpler concepts, fewer cases,
less repetition.

It's about how much you have to think about, now how much you
have to read/write.
December 24, 2011
On 12/25/2011 12:27 AM, Adam D. Ruppe wrote:
> On Saturday, 24 December 2011 at 23:12:27 UTC, bearophile wrote:
>> I was talking about the abundance of (({}){()}) and not about
>> identifiers length.
>
> It's the same fallacy.

Not really. Functional style code tends to be conceptually simpler. Having code that is more readable can help. Getting rid of (({return {return}}){return()}) makes the code more readable, whereas excessively shortening identifiers does the opposite.

See here for an example of what bearophile is talking about:
http://pastebin.com/2rEdx0RD

However, I think the slow druntime GC is more of a show stopper for functional D than any syntactic issues there may be.

> I can't read Carmack's mind, but
> I'm sure he's talking about shortening code the same way
> I would mean it if I said it - simpler concepts, fewer cases,
> less repetition.
>
> It's about how much you have to think about, now how much you
> have to read/write.

I am quite sure he is talking about character count. I still think you are right, because for reasonable code with average identifier lengths etc. character count correlates a good bit with what you suggest are good measures for code length.
December 24, 2011
Adam D. Ruppe:

> It's the same fallacy. I can't read Carmack's mind, but
> I'm sure he's talking about shortening code the same way
> I would mean it if I said it - simpler concepts, fewer cases,
> less repetition.

In a medium sized program there are many different ways to reduce redundancy and repetition, at various levels. Example: modules found online are a good way to avoid writing some chunks of your program yourself. Using certain abstractions sometimes helps to write one idea only once in a program. Etc.

Another significant way to remove repetition at a very different level is to use micro-patterns like higher order functions, like map and filter, and other std.algorithm functions like canFind, count, etc, plus iterators like zip, etc. If you use them you are often able to reduce the code _significantly_ and make it more explicit (because if you use std.algorithm.count the person that reads the code knows you are counting).

But a problem is that such D code is full of braces and parentheses that make such code hard to read and write (I agree with Andrei that D is not very designed for such kind of code, but the fact doesn't change).

Bye,
bearophile
December 25, 2011
On Sun, 25 Dec 2011 01:51:57 +0200, bearophile <bearophileHUGS@lycos.com> wrote:

> But a problem is that such D code is full of braces and parentheses that make such code hard to read and write (I agree with Andrei that D is not very designed for such kind of code, but the fact doesn't change).

Absolutely agree braces and parens are ugly and unreadable.
Yet if your solution to this particular case is functional syntax, i disagree.
It doesn't make it readable, at least when you are not writing "sample" code.
When things get ugly (they do) braces and parens are your only friends.

Whenever i see those that suggest tabs instead of braces, i can't help thinking that they just write "sample" code.

I would love to have "a => a*a" for only lambdas but for generic case i haven't seen anything that could replace parens and braces.
December 25, 2011
On Saturday, 24 December 2011 at 23:44:11 UTC, Timon Gehr wrote:
> Functional style code tends to be conceptually simpler.

I find bugs creep into things with lots of parameters
or conditions. For instance:

if((flag && request.isSomething()) || request.isSomethingElse()) {}

If you have a lot of stuff like that, it's hard to tell what
code is actually running, which makes working with it hard,
even if the other stuff is simple.

This tends to have a good chunk of repetition too, inflating
the size, since you're doing many custom paths for all the
conditions. And that's where you miss stuff.

(On the other hand, I don't have a lot of experience working with
non-example functional code, so maybe this tends to be avoided there?)
December 25, 2011
On Saturday, 24 December 2011 at 23:51:57 UTC, bearophile wrote:
> Using certain abstractions sometimes helps to write one idea only once in a program. Etc.

This is the biggest one, and applies to all kinds of code.
I like to write little functions with meaningful names.

bool isOdd(int i) {
   if((i % 2) == 0)
       return false;
   else
       return true;
}

filter!isOdd(myCollection);


I find that nicer than

filter!"i % 2 != 0"(myCollection);

despite it being longer.

With the former, it says very simply that it wants odd
numbers at the usage location.


With the latter, you have to think for a second about
what the modulus operator actually does and what the
definition of an odd number is before you can get to
why the filter is there at all.


It gets even worse if the other function has non-trivial
code. Best to just give it a name so you don't have to think
about the implementation at all at the usage site.
December 25, 2011
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.

On 24/12/2011 9:33 AM, Andrei Alexandrescu wrote:
>
> Anyhow, is there anything you have in mind that we have the chance of
> improving at this point?
>

December 25, 2011
On 12/24/2011 05:44 PM, Timon Gehr wrote:
> On 12/25/2011 12:27 AM, Adam D. Ruppe wrote:
>> On Saturday, 24 December 2011 at 23:12:27 UTC, bearophile wrote:
>>> I was talking about the abundance of (({}){()}) and not about
>>> identifiers length.
>>
>> It's the same fallacy.
>
> Not really. Functional style code tends to be conceptually simpler.
> Having code that is more readable can help. Getting rid of (({return
> {return}}){return()}) makes the code more readable, whereas excessively
> shortening identifiers does the opposite.
>
> See here for an example of what bearophile is talking about:
> http://pastebin.com/2rEdx0RD

I looked over that code. It creates an entire lazy evaluation environment. It's quite remarkable it's actually so concise, and I don't see a lot of ways to significantly improve it.

> However, I think the slow druntime GC is more of a show stopper for
> functional D than any syntactic issues there may be.

Got the GC book this morning, already read 2.5 chapters :o).


Andrei

December 25, 2011
On 12/24/2011 07:20 PM, Adam D. Ruppe wrote:
> On Saturday, 24 December 2011 at 23:51:57 UTC, bearophile wrote:
>> Using certain abstractions sometimes helps to write one idea only once
>> in a program. Etc.
>
> This is the biggest one, and applies to all kinds of code.
> I like to write little functions with meaningful names.
>
> bool isOdd(int i) {
> if((i % 2) == 0)
> return false;
> else
> return true;
> }
>
> filter!isOdd(myCollection);
>
>
> I find that nicer than
>
> filter!"i % 2 != 0"(myCollection);
>
> despite it being longer.

Different strokes for different folks. IMHO it would be difficult to justify the verboseness and the unnecessary (twice) flow of control. I see every letter beyond this as a liability:

bool isOdd(int i)
{
    return (i & 1) != 0;
}

> With the former, it says very simply that it wants odd
> numbers at the usage location.

Giving an operation, however trivial, a symbol, is often a good thing. There are of course limits, and each engineer has their own ideas where to draw the line.


Andrei