D component programming is a joke (Was: Re: Component programming)

bearophile bearophileHUGS at lycos.com
Sat Aug 3 20:02:05 PDT 2013


H. S. Teoh:

> OK, here's a draft of the article:
>
> 	http://wiki.dlang.org/User:Quickfur/Component_programming_with_ranges


Most of the code below is not tested. So my suggestions may 
contain bugs or mistakes.


A bit improved chunkBy could go in Phobos.

---------------

>For our purposes, though, we can't just do this in a loop, 
>because it has to interface with the other components, which do 
>not have a matching structure to a loop over dates.<

It's just because D doesn't yet have a yield designed like C#. 
"yield" for coroutines is a very nice kind of glue.

---------------

auto datesInYear(int year) {
     return Date(year, 1, 1)
         .recurrence!((a,n) => a[n-1] + dur!"days"(1))
         .until!(a => a.year > year);
}


===>


auto datesInYear(in uint year) pure /*nothrow*/
in {
     assert(year > 1900);
} body {
     return Date(year, 1, 1)
            .recurrence!((a, n) => a[n - 1] + dur!"days"(1))
            .until!(d => d.year > year);
}


I suggest to align the dots vertically like that. And generally 
_all_ variables/arguments that don't need to mutate should be 
const or immutable (or enum), unless holes in Phobos or in the 
type system or other factors prevent you to do it.

---------------

return chunkBy!"a.month()"(dates);

===>

return dates.chunkBy!q{ a.month };

---------------

byWeek() is not so simple. Most of its code is boilerplate code. 
Perhaps using a "yield" it becomes simpler.

---------------

string spaces(size_t n) {
     return repeat(' ').take(n).array.to!string;
}

===>

string spaces(in size_t n) pure nothrow {
     return std.array.replicate(" ", n);
}


Currently in programs that import both std.range and std.array 
you have to qualify the module for replicate.

In Python this is just:

' ' * n

---------------

auto buf = appender!string();

Perhaps this suffices:

appender!string buf;

---------------

string[] days = map!((Date d) => " %2d".format(d.day))(r.front)
                 .array;

(not tested) ==>

const days = r.front.map!(d => " %2d".format(d.day)).array;

Or:

const string[] days = r
                       .front
                       .map!(d => " %2d".format(d.day))
                       .array;

---------------

If you put the days inside buf, do you really need to turn days 
into an array with array()?

string[] days = map!((Date d) => " %2d".format(d.day))(r.front)
                 .array;
assert(days.length <= 7 - startDay);
days.copy(buf);


Isn't this enough?

auto days = r.front.map!(d => " %2d".format(d.day));

---------------

If not already present this array should go in std.datetime or 
core.time:

     static immutable string[] monthNames = [
         "January", "February", "March", "April", "May", "June",
         "July", "August", "September", "October", "November", 
"December"
     ];

---------------

return to!string(spaces(before) ~ name ~ spaces(after));

==> (untested)

return text(before.spaces, name, after.spaces);

Or maybe even just (untested):

return before.spaces ~ name ~ after.spaces;

---------------

auto formatMonth(Range)(Range monthDays)
     if (isInputRange!Range && is(ElementType!Range == Date))
{
     assert(!monthDays.empty);
     assert(monthDays.front.day == 1);

     return chain(
         [ monthTitle(monthDays.front.month) ],
         monthDays.byWeek().formatWeek());
}

===> (untested)

auto formatMonth(R)(R monthDays)
     if (isInputRange!R && is(ElementType!R == Date))
in {
     assert(!monthDays.empty);
     assert(monthDays.front.day == 1);
} body {
     return [monthDays.front.month.monthTitle]
            .chain(monthDays.byWeek.formatWeek);
}


Generally I suggest to use pre- and post conditions.

---------------

return months.map!((month) => month.formatMonth());

===> (untested)

return months.map!formatMonth;

---------------

.map!((r) =>

===>

.map!(r =>

---------------

int year = to!int(args[1]);

===>

int year = args[1].to!int;

---------------

On Rosettacode there is a shorter calendar:
http://rosettacode.org/wiki/Calendar#D

If you want we can put, as second D entry, your calendar code 
(without unittests) in that page too.

Bye,
bearophile


More information about the Digitalmars-d mailing list