August 01, 2013
Walter Bright:

> But consider that optimizers are built to optimize typical code patterns. Component programming is fairly non-existent in C and C++, and is new in D. Hence, optimizers are not set up to deal with those patterns (yet).

I agree.

GHC also works with a LLVM back-end, so those optimizations are done in some kind of middle-end.

Probably a silly idea: perhaps we can collect some money, like 1000-2000 dollars, to pay for a 3 day long course for Walter (total about 15 hours) about such matters.

Bye,
bearophile
August 02, 2013
On Thu, Aug 01, 2013 at 10:34:24AM -0700, Walter Bright wrote:
> On 8/1/2013 2:23 AM, John Colvin wrote:
> >On Thursday, 1 August 2013 at 00:47:43 UTC, H. S. Teoh wrote: Add in some code examples and that could make a nice article.
> 
> Yes, please!

Alright, so I decided to prove my point about component programming by actually writing a fully-functional version of the calendar layout program, so that I have a solid piece of evidence that component programming lives up to its promise. :) In addition, I decided that for maximum reusability, I want the output lines available in an input range, with absolutely no binding to writeln whatsoever (except in main() where the range is handed to writeln for output). In retrospect, that was perhaps a bit too ambitious... I ran into a few roadblocks to actually get the code working, so it took me a lot longer than I anticipated to finish the code.

However, I *will* say that I'm very proud of the code: already there are a few pieces that, if properly cleaned up and refined, probably deserve inclusion in Phobos. Reusability FTW!! Now, just tell me if you've ever seen a calendar layout program made of straightforward, reusable pieces. I for sure haven't. I tried looking at the C code for the Unix cal program once... It looked frighteningly similar to an IOCCC entry. :-/

My D version, however, built using ranges through and through, has many pieces that are easily reusable. For example, if you wanted to output only a single month instead, you could just call join("\n") on the range of formatted month lines that the full year layout algorithm uses to splice lines from multiple months together -- it's *that* reusable.

Anyway. Enough hand-waving in the air. Let the actual code speak for itself:

	https://github.com/quickfur/dcal/blob/master/dcal.d

Now, w.r.t. the roadblocks I alluded to.

When I first started working on the code, my goal was to maximize usage of existing Phobos facilities in order to show how many batteries D already comes with. As it turned out, I could only use basic Phobos components; some of the more complex pieces like frontTransversal, which would've been perfect for the bit that splices formatted month lines together, couldn't be used because it wasn't flexible enough to handle the insertion of fillers when some subranges are empty. In the end, I had to code that range by hand, and I can't say I'm that happy with it yet. But at least, it's nothing compared to the hairy complexity of the C version of cal.

Another place where I wanted to use existing Phobos components was chunkBy. There's probably a way to do it if you think hard enough about it, but in the end I felt it was simpler to just write the code myself. Might be a failure on my part to recognize how to put existing Phobos ranges in a clever enough way to achieve what I wanted. I did try to do something similar to byWeek(), but somehow it didn't do what I wanted and I decided to just code it by hand instead of investigating further.

By far the biggest roadblock I ran into was that after I wrote everything up to (and including) pasteBlocks, my unittests refused to work. Somehow, pasteBlocks kept repeating the first line of the output (the month names, if you look at the unittest) and refused to advance farther.  Eventually I traced the problem to Lines.popFront(), which pops each subrange off the range of ranges. The problem is that this only works on some ranges, but not others; if you pass the output of formatMonths() straight to pasteBlocks(), it will NOT work. Why? Because pasteBlocks return a std.algorithm.Map object, which recreates the subrange each time, so Lines.popFront() is only popping a temporary copy of the subrange, not the real thing. I was about to give up and try another approach, when out of the blue I decided to try and see if I could stuff the range returned by formatMonths() into an array, and then pass *that* to pasteBlocks() -- and behold, it worked!!

This was a totally unexpected fix, that a newbie probably would never have thought of, so this is a potential trap for newcomers to D who expect components to just be pluggable. In retrospect, it makes sense -- you need to somehow buffer the ranges of formatted month lines *somewhere* in order to be able to splice them together out of their natural depth-first outer/inner range order. But this is not obvious at all from first glance; perhaps it's a sign of a leaky abstraction somewhere. We should probably look into why this is happening and how to fix it. And there should be a way to test for this in pasteBlocks' signature constraint so that future code won't fall into the same trap, but I can't think of one right now.

Once this last bit worked, though, everything fell into place quickly. After all unittests were passing, no more bugs were found!! The program can print beautifully laid out calendars with no problems whatsoever. I'm so in love with D right now... If I'd done this exercise in C or C++, I'd be spending the next 2 days debugging before I could present the code for the world to see. D ranges and unittest blocks are t3h k00l.


T

-- 
It always amuses me that Windows has a Safe Mode during bootup. Does that mean that Windows is normally unsafe?
August 02, 2013
On 8/1/2013 10:24 PM, H. S. Teoh wrote:
> Once this last bit worked, though, everything fell into place quickly.
> After all unittests were passing, no more bugs were found!! The program
> can print beautifully laid out calendars with no problems whatsoever.
> I'm so in love with D right now... If I'd done this exercise in C or
> C++, I'd be spending the next 2 days debugging before I could present
> the code for the world to see. D ranges and unittest blocks are t3h
> k00l.

I think this is awesome, and this + your previous post are sufficient to create a great article!

August 02, 2013
On Wednesday, 31 July 2013 at 10:20:57 UTC, Chris wrote:
> This is only losely related to D, but I don't fully understand the separation of component programming and OOP (cf. https://en.wikipedia.org/wiki/Component-based_software_engineering#Differences_from_object-oriented_programming). In an OO framwork, the objects are basically components. See also
>
> "Brad Cox of Stepstone largely defined the modern concept of a software component.[4] He called them Software ICs and set out to create an infrastructure and market for these components by inventing the Objective-C programming language." (see link above)
>
> Walter's example (http://www.drdobbs.com/architecture-and-design/component-programming-in-d/240008321)
>
> void main() {
>         stdin.byLine(KeepTerminator.yes)    // 1
>         map!(a => a.idup).                  // 2
>         array.                              // 3
>         sort.                               // 4
>         copy(                               // 5
>             stdout.lockingTextWriter());    // 6
>     }
>
> This is more or less how mature OO programs look like. Ideally each class (component) does one thing (however small the class might be) and can be used or called to perform this task. All other classes or components can live independently. From my experience this is exactly what Objective-C does. Rather than subclassing, it uses other classes to get a job done.

A few days ago, there was a discussion about APL on HN [0]. What we call Component Programming here, looks somewhat like the APL style to me. Sure, APLers have a single weird symbol for stuff like "sort.", but this chaining of powerful modular operations is what APL seems to be all about.

The APL paradigm is not integrated into modern languages so far. I am excited that it might make an introduction now. Compare for example Functional Programming, which is integrated into most mainstream languages by now. Or Logic Programming, which seems not worthy enough to get its own syntax, but is available in the business rules world with libraries and DSLs and its minor brother Datalog is also still alive.

[0] https://news.ycombinator.com/item?id=6115727
August 02, 2013
On Thu, 01 Aug 2013 22:24:32 -0700, H. S. Teoh wrote:
> Now, w.r.t. the roadblocks I alluded to.
> 
> When I first started working on the code, my goal was to maximize usage of existing Phobos facilities in order to show how many batteries D already comes with. As it turned out, I could only use basic Phobos components; some of the more complex pieces like frontTransversal, which would've been perfect for the bit that splices formatted month lines together, couldn't be used because it wasn't flexible enough to handle the insertion of fillers when some subranges are empty. In the end, I had to code that range by hand, and I can't say I'm that happy with it yet.

I recently wrote a range component for my current project that is similar but with a twist.  It takes a bunch of ranges, each of which is assumed to be sorted with some predicate, then it walks through them, returning a range of the fronts of each range. The twist is that it has to call a user-supplied `produce` function whenever it encounters a mismatch (e.g. a range's front is greater than the others or a range is empty).
August 02, 2013
On Fri, Aug 02, 2013 at 04:06:46PM +0000, Justin Whear wrote:
> On Thu, 01 Aug 2013 22:24:32 -0700, H. S. Teoh wrote:
> > Now, w.r.t. the roadblocks I alluded to.
> > 
> > When I first started working on the code, my goal was to maximize usage of existing Phobos facilities in order to show how many batteries D already comes with. As it turned out, I could only use basic Phobos components; some of the more complex pieces like frontTransversal, which would've been perfect for the bit that splices formatted month lines together, couldn't be used because it wasn't flexible enough to handle the insertion of fillers when some subranges are empty. In the end, I had to code that range by hand, and I can't say I'm that happy with it yet.
> 
> I recently wrote a range component for my current project that is similar but with a twist.  It takes a bunch of ranges, each of which is assumed to be sorted with some predicate, then it walks through them, returning a range of the fronts of each range. The twist is that it has to call a user-supplied `produce` function whenever it encounters a mismatch (e.g.  a range's front is greater than the others or a range is empty).

It would be nice to collect these custom ranges and see if there's some common functionality that can be added to Phobos.


T

-- 
The trouble with TCP jokes is that it's like hearing the same joke over and over.
August 02, 2013
H. S. Teoh:

> It would be nice to collect these custom ranges and see if there's some common functionality that can be added to Phobos.

chunkBy seems OK for Phobos.

Bye,
bearophile
August 02, 2013
On 08/02/2013 07:24 AM, H. S. Teoh wrote:
> ...
> Anyway. Enough hand-waving in the air. Let the actual code speak for
> itself:
>
> 	https://github.com/quickfur/dcal/blob/master/dcal.d
> ...

Which version of the compiler are you using?

I get the dreaded forward reference errors with at least DMD 2.060, DMD 2.063 and DMD 2.063.2 and the 2.x build on dpaste.

Git head gives me:

Error: undefined identifier '_xopCmp'
dmd: clone.c:690: FuncDeclaration* StructDeclaration::buildXopCmp(Scope*): Assertion `s' failed.
Aborted (core dumped)
August 02, 2013
On Fri, Aug 02, 2013 at 08:49:30PM +0200, Timon Gehr wrote:
> On 08/02/2013 07:24 AM, H. S. Teoh wrote:
> >...
> >Anyway. Enough hand-waving in the air. Let the actual code speak for
> >itself:
> >
> >	https://github.com/quickfur/dcal/blob/master/dcal.d
> >...
> 
> Which version of the compiler are you using?

I'm using git HEAD.


> I get the dreaded forward reference errors with at least DMD 2.060, DMD 2.063 and DMD 2.063.2 and the 2.x build on dpaste.

Can you send me the error messages? I'll see if I can reorder the code to fix them.


> Git head gives me:
> 
> Error: undefined identifier '_xopCmp'
> dmd: clone.c:690: FuncDeclaration*
> StructDeclaration::buildXopCmp(Scope*): Assertion `s' failed.
> Aborted (core dumped)

That's new. It was working as of yesterday; must've been a new regression in the commits since then?


T

-- 
The richest man is not he who has the most, but he who needs the least.
August 02, 2013
On Fri, Aug 02, 2013 at 03:00:01PM -0700, H. S. Teoh wrote:
> On Fri, Aug 02, 2013 at 08:49:30PM +0200, Timon Gehr wrote:
[...]
> > I get the dreaded forward reference errors with at least DMD 2.060, DMD 2.063 and DMD 2.063.2 and the 2.x build on dpaste.
> 
> Can you send me the error messages? I'll see if I can reorder the code to fix them.

I just checked DMD 2.063, and it appears that the error is caused by a limitation in std.range.chunks in 2.063, where it requires slicing and length, but formatYear can only give it an input range. This is kinda sad, since that means I'll have to implement chunks myself on 2.063. :-/

I've no idea why it seems to be somehow conflated with an error from invoking std.conv.to!() to convert from string to int; apparently some kind of compiler bug that obscures the real problem with std.range.chunks.


> > Git head gives me:
> > 
> > Error: undefined identifier '_xopCmp'
> > dmd: clone.c:690: FuncDeclaration*
> > StructDeclaration::buildXopCmp(Scope*): Assertion `s' failed.
> > Aborted (core dumped)
> 
> That's new. It was working as of yesterday; must've been a new regression in the commits since then?
[...]

Actually, I just pulled git HEAD again, and it's still working fine. Maybe you just need to update your repo?


T

-- 
"Real programmers can write assembly code in any language. :-)" -- Larry Wall