March 18, 2015
On Friday, 13 March 2015 at 17:31:09 UTC, Andrei Alexandrescu wrote:
>
> For example the expression (assuming s is e.g. a string)
>
>   File("/tmp/a").byChunk(4096).joiner.startsWith(s)
>
> opens a file, progressively reads chunks of 4KB, stitches them together at no cost, compares against a prefix until it makes a decision, then closes the file and returns the result. A putative Go user wouldn't even dream of using HasPrefix directly on a stream coming from a file; the whole endeavor would be a function that painstakingly takes all of these steps by hand.

I personally, would have no idea what this piece of code is doing
upon first sight. I'll have to look at the documentation of
at least two functions to understand that, and I'll have to
think carefully about what and who would throw in case of an error.

Something like

    while (n != EOF) {
        n = read(fd, buf, sizeof(buf));
        if (n==-1) throw(...);
        if (strcmp(buf, PREFIX) == 0) {
             return buf;
        }
    }
    return NULL;

Requires no prior knowledge, and have similar effect.

I'd rather have a loop written by hand in my production code any day,
so that when debugging it, and reading it I'll have easier time
to understand it, even though it would cost me a few more lines
when writing the code.

What if this pattern repeats a few times in the code?

I'd rather have a single function that have the explicit loop than
having this pattern in slight variations spread in the code.

Writing code is easy, maintaining it afterwards is costly.
March 18, 2015
Elazar Leibovich:

> I personally, would have no idea what this piece of code is doing upon first sight. I'll have to look at the documentation of
> at least two functions to understand that, and I'll have to
> think carefully about what and who would throw in case of an error.
>
> Something like
>
>     while (n != EOF) {
>         n = read(fd, buf, sizeof(buf));
>         if (n==-1) throw(...);
>         if (strcmp(buf, PREFIX) == 0) {
>              return buf;
>         }
>     }
>     return NULL;
>
> Requires no prior knowledge, and have similar effect.
>
> I'd rather have a loop written by hand in my production code any day, so that when debugging it, and reading it I'll have easier time
> to understand it, even though it would cost me a few more lines
> when writing the code.

Unfortunately your thinking is mostly obsolete, the programming world (well, most of it, Go is one exception) is going in the opposite direction, and for good reasons. An explanation:
https://channel9.msdn.com/Events/GoingNative/2013/Cpp-Seasoning

Bye,
bearophile
March 18, 2015
On Wednesday, 18 March 2015 at 01:52:00 UTC, Laeeth Isharc wrote:
> On Tuesday, 17 March 2015 at 21:00:11 UTC, bachmeier wrote:
>> On Tuesday, 17 March 2015 at 19:00:06 UTC, jmh530 wrote:
>>> In addition, further development of the ability to call D from R or Python* or Julia (or vice-versa) would also be a positive.
>>
>> What do you have in mind? I no longer work much with Python so my knowledge is limited, but calling D from R or Julia should be no different from calling C from those languages, as you normally compile your C code into a shared library anyway.
>>
>> I've done the R->D thing many times and in the process have worked with a big chunk of the R API. Things like allocating R data structures from a D function, adding assertions to your D code to allow for an easy exit when things don't work out, and calling functions in the R math library, among other things, are not difficult.
>
> PyD is pretty nice, although one wouldn't want to call it from an inner loop.  And it's easy to go via cython also.  (I wonder how well cython works with interfacing with D via the C++ interface, because that way you could extend python with D classes and have them be faster than going through PyD).
>
> PyD also works with numpy memoryviews I think.
>
> For Julia, easy to call D.  It would be nice to port julia.h to D (I started, but got distracted) so D can call back Julia.

I once wrote a little test server with vibe.d and LuaD to have Lua server pages. It compiles the pages into Lua functions and executes them from memory. (Rikki gave me the idea). No use to parse every page when it's called.

It's not much code at all. It's only a test and very simple, not optimized or anything. The function in vibe.d that handled it looks like this:

/**
* Function that handles LSP using LuaD and a home made
* parser.
*/
void luaHandler(HTTPServerRequest req, HTTPServerResponse res) {

  auto url = URL(req.requestURL);

  // Set url arguments (note: should decode URL)
  lua["args"] = req.query;

  // If html/lsp page is not yet compiled, parse, compile and store it in _S
  if (!canFind(_S.keys, url.pathString[1..$])) {
    auto file = std.stdio.File("public/"~url.pathString[1..$], "r");
    string txt;
    foreach (line; file.byLine(KeepTerminator.yes)) {
      txt ~= to!string(line);  // to!string really necessary?
    }
    auto asLua = parseLua(txt);
    auto func = lua.loadString(asLua);
    _S[url.pathString[1..$]] = func;
  }
  // Call the compiled Lua function
  auto ret = _S[url.pathString[1..$]].call!(LuaTable)();
  string html;
  foreach(size_t i, string s; ret) {
    html ~= s;
  }
  res.writeBody(cast(ubyte[])html);
}
March 18, 2015
On Wednesday, 18 March 2015 at 12:11:52 UTC, bearophile wrote:
> Elazar Leibovich:
>
>> I personally, would have no idea what this piece of code is doing upon first sight. I'll have to look at the documentation of
>> at least two functions to understand that, and I'll have to
>> think carefully about what and who would throw in case of an error.
>>
>> Something like
>>
>>    while (n != EOF) {
>>        n = read(fd, buf, sizeof(buf));
>>        if (n==-1) throw(...);
>>        if (strcmp(buf, PREFIX) == 0) {
>>             return buf;
>>        }
>>    }
>>    return NULL;
>>
>> Requires no prior knowledge, and have similar effect.
>>
>> I'd rather have a loop written by hand in my production code any day, so that when debugging it, and reading it I'll have easier time
>> to understand it, even though it would cost me a few more lines
>> when writing the code.
>
> Unfortunately your thinking is mostly obsolete, the programming world (well, most of it, Go is one exception) is going in the opposite direction, and for good reasons. An explanation:
> https://channel9.msdn.com/Events/GoingNative/2013/Cpp-Seasoning
>
> Bye,
> bearophile

Bearophile,

You said that "Unfortunately" this thinking is going out of style "for good reasons".   I am confused (sorry, I am at work, and didn't have time to watch the 1+ hour video you linked to - maybe some clues were there)!

I often find myself feeling a bit like Elazar.  Not long ago I wrote some Python code using a bunch of the functional style programming tools and I was very please with the very concise code I had generated.  Then, I had to make some modifications to the code. It took me an inordinate amount of time just to figure out what the code was doing, and I had written it myself just a few days earlier!

Craig

March 18, 2015
CraigDillabaugh:

> You said that "Unfortunately" this thinking is going out of style "for good reasons".   I am confused (sorry, I am at work, and didn't have time to watch the 1+ hour video you linked to -

I said "unfortunately" because it's another reason for us to refactor and change our coding habits :-)



> maybe some clues were there)!

Of course.


> I often find myself feeling a bit like Elazar.  Not long ago I wrote some Python code using a bunch of the functional style programming tools and I was very please with the very concise code I had generated.  Then, I had to make some modifications to the code. It took me an inordinate amount of time just to figure out what the code was doing, and I had written it myself just a few days earlier!

There's not a single correct answer to this. Replacing long bug-prone explicit-loops code with pre-made safer algorithms is often a good idea. The effort of learning some very generic and reusable functions is usually worth it. But I've also seen plenty of Haskell code that requires you to know tens of tiny functions, often named with symbols like !<>!. This is worse than writing for loops. High level constructs in D are often slower than low-level code, so in some cases you don't want to use them.

So as usually you have to choose wisely, because most solutions aren't perfect if you use them everywhere, there are many ways to write bad code if you don't keep your eyes and brain switched on.

Bye,
bearophile
March 18, 2015
On Wednesday, 18 March 2015 at 12:45:50 UTC, CraigDillabaugh wrote:
> On Wednesday, 18 March 2015 at 12:11:52 UTC, bearophile wrote:
>> Elazar Leibovich:
>>
>>> I personally, would have no idea what this piece of code is doing upon first sight. I'll have to look at the documentation of
>>> at least two functions to understand that, and I'll have to
>>> think carefully about what and who would throw in case of an error.
>>>
>>> Something like
>>>
>>>   while (n != EOF) {
>>>       n = read(fd, buf, sizeof(buf));
>>>       if (n==-1) throw(...);
>>>       if (strcmp(buf, PREFIX) == 0) {
>>>            return buf;
>>>       }
>>>   }
>>>   return NULL;
>>>
>>> Requires no prior knowledge, and have similar effect.
>>>
>>> I'd rather have a loop written by hand in my production code any day, so that when debugging it, and reading it I'll have easier time
>>> to understand it, even though it would cost me a few more lines
>>> when writing the code.
>>
>> Unfortunately your thinking is mostly obsolete, the programming world (well, most of it, Go is one exception) is going in the opposite direction, and for good reasons. An explanation:
>> https://channel9.msdn.com/Events/GoingNative/2013/Cpp-Seasoning
>>
>> Bye,
>> bearophile
>
> Bearophile,
>
> You said that "Unfortunately" this thinking is going out of style "for good reasons".   I am confused (sorry, I am at work, and didn't have time to watch the 1+ hour video you linked to - maybe some clues were there)!
>
> I often find myself feeling a bit like Elazar.  Not long ago I wrote some Python code using a bunch of the functional style programming tools and I was very please with the very concise code I had generated.  Then, I had to make some modifications to the code. It took me an inordinate amount of time just to figure out what the code was doing, and I had written it myself just a few days earlier!
>
> Craig

Maybe your years of practice and deep familiarity with imperative code patterns - both general and individual to yourself - might have skewed the result somewhat.

It seems to me that much of practical programming is about having set up "quick paths" in your brain for recognising and manipulating common patterns. There's a big gap between understanding something intellectually and understanding something intuitively.
March 18, 2015
> A priori I do not believe the claim made here: a GPars task is submitted
> to a thread pool, which is exactly what the goroutines are. Thus the
> number of Java threads is not a bound on the number of GPars tasks. Any
> bounds will be provided by the Fork/Join pool.

Here is a GPars sample from http://www.gpars.org/1.0.0/guide/guide/GroovyCSP.html

final class Copy implements Callable {
    private final DataflowChannel inChannel
    private final DataflowChannel outChannel1
    private final DataflowChannel outChannel2

public def call() {
	final PGroup group = Dataflow.retrieveCurrentDFPGroup()
	while (true) {
		def i = inChannel.val
		group.task {
			outChannel1 << i
			outChannel2 << i
		}.join()
	}
}

If inChannel.val blocks, the thread serving the Copy instance is blocked and lost for serving other channels. If this happens several times the JVM has run out of threads and the application is in limbo.

This is not the case in Go. When a goroutine is blocked by a blocking take on an empty channel, the Go scheduler withdraws the thread serving this goroutine and assigns it to some other goroutine.
March 18, 2015
clip

>> Bearophile,
>>
>> You said that "Unfortunately" this thinking is going out of style "for good reasons".   I am confused (sorry, I am at work, and didn't have time to watch the 1+ hour video you linked to - maybe some clues were there)!
>>
>> I often find myself feeling a bit like Elazar.  Not long ago I wrote some Python code using a bunch of the functional style programming tools and I was very please with the very concise code I had generated.  Then, I had to make some modifications to the code. It took me an inordinate amount of time just to figure out what the code was doing, and I had written it myself just a few days earlier!
>>
>> Craig
>
> Maybe your years of practice and deep familiarity with imperative code patterns - both general and individual to yourself - might have skewed the result somewhat.
>
> It seems to me that much of practical programming is about having set up "quick paths" in your brain for recognising and manipulating common patterns. There's a big gap between understanding something intellectually and understanding something intuitively.

There is quite possibly something too that, and as I imagine
with more functional experience it will come easier to me.

However, I still think imperative code is generally easier to
reason about because (usually) each line of code is performing
a single task, whereas with functional coding the goal seems
to be to cram as many operations as possible into a single line
(I know that isn't the real reason, it just seems that way at
times).  Trying to 'unroll' everything in your head can be a
challenge.  Throw in a lambda function or two with
the mess of braces/symbols and then you have a real puzzler.
March 18, 2015
On Wednesday, 18 March 2015 at 12:45:50 UTC, CraigDillabaugh wrote:
> On Wednesday, 18 March 2015 at 12:11:52 UTC, bearophile wrote:
>> Elazar Leibovich:
>>
>>> I personally, would have no idea what this piece of code is doing upon first sight. I'll have to look at the documentation of
>>> at least two functions to understand that, and I'll have to
>>> think carefully about what and who would throw in case of an error.
>>>
>>> Something like
>>>
>>>   while (n != EOF) {
>>>       n = read(fd, buf, sizeof(buf));
>>>       if (n==-1) throw(...);
>>>       if (strcmp(buf, PREFIX) == 0) {
>>>            return buf;
>>>       }
>>>   }
>>>   return NULL;
>>>
>>> Requires no prior knowledge, and have similar effect.
>>>
>>> I'd rather have a loop written by hand in my production code any day, so that when debugging it, and reading it I'll have easier time
>>> to understand it, even though it would cost me a few more lines
>>> when writing the code.
>>
>> Unfortunately your thinking is mostly obsolete, the programming world (well, most of it, Go is one exception) is going in the opposite direction, and for good reasons. An explanation:
>> https://channel9.msdn.com/Events/GoingNative/2013/Cpp-Seasoning
>>
>> Bye,
>> bearophile
>
> Bearophile,
>
> You said that "Unfortunately" this thinking is going out of style "for good reasons".   I am confused (sorry, I am at work, and didn't have time to watch the 1+ hour video you linked to - maybe some clues were there)!
>
> I often find myself feeling a bit like Elazar.  Not long ago I wrote some Python code using a bunch of the functional style programming tools and I was very please with the very concise code I had generated.  Then, I had to make some modifications to the code. It took me an inordinate amount of time just to figure out what the code was doing, and I had written it myself just a few days earlier!
>
> Craig

Simple solution: use comments :-)
March 18, 2015
On Tuesday, 17 March 2015 at 21:16:38 UTC, Carl Sturtivant wrote:
>
>
> Characterizing the problem as "Go versus D" is framing it to D's disadvantage. Broadly speaking Go is one thing & D is many things.
>
> The whole difficulty with D encountered by a person choosing which of (e.g.) Go and D to use lies in this difference. D as a whole is overwhelming in this situation.
>
> D may be spoken naturally in many different ways. This is its strength. We need to make this strength accessible to outsiders. If an outsider can speak D at first in a way somewhat familiar from their previous experience, that will provide accessibility.
>
> We may classify outsiders as coming from C, C++, Java, Python, Go and more. Make your own list.
>
> Each kind of outsider needs to see an approximate reflection in D of the machinery of their usual means of expression and its attendant conceptual models, plus exciting possibilities to improve and extend these. This reflection must be made workable on all scales, from details of idioms and techniques up to the big picture.
>
> An outsider needs a well developed specialized way in! One that is designed for that specific class of outsider. Given such, in the short run the D written by one class of outsider will be quite different in its use of the language to that written by another, which will be quite different again to that written by contributors to phobos.
>
> We should accept this. They may expand their horizons within D later. The community may find ways to help such people do this, for example by gently suggesting better parts of D to use for technical parts of their purposes when they post to the forums. In the meantime they have come to D because there was a relatively efficient way for them to do that, not a bewildering collection of possibilities that deflected them to the certainties of the overly prescribed ways of (e.g.) Go.
>
> Now consider outsiders from C, C++, Java, Python, Go.
>
> I'll leave you to consider C, C++. The articles
>   http://dlang.org/ctod.html
>   http://dlang.org/cpptod.html
>   http://dlang.org/pretod.html
> have made a detail-oriented start with tacit assumptions about what is going on at wider scales. These languages are closely entangled with D's development, and so are special cases given better treatment. These could be expanded into an entire introduction to D for C outsiders and an entire introduction to D for C++ outsiders.
>
> Java is not too hard especially given the design of D's classes. Java is almost a small sublanguage of D.
>
> Python and Go are harder. But D is a system programming language with [long list of powerful abstraction facilities, many supported paradigms, "wonderfulness of D"]. And as such one may hope it is possible to arrange to program in D in Pythonesque or Goish ways. Especially if this provides a way for D to win rather than lose out to these languages, by providing an incremental way in.
>
> The yield facility in Python can serve as a first example here. This is not a part of the D language. The Fiber class in core.thread can be made to emulate it with additional superstructure with some effort. But this is exactly the kind of effort an outsider from Python is not immediately equipped to make. Go's goroutine and its attendant machinery could be examined with a similar end in view.
>
> What all of this suggests is that some library code may need to be written to accomodate the way into D for a class of outsiders. The administration of where such goes needs to make it simple to import with a standard D installation. And if D is too inflexible to provide something important via a library, as is possibly the case with yield, serious consideration should be given to (don't scream) adding it to the language.
>
> In conclusion, D is not gaining the traction it deserves as a potential lingua franca. I am making the case that we need to treat it as several programming languages for the purpose of making it rapidly usable by typical outsiders. D-python, D-java, D-whatever --- facets of D.
>
> This entails library additions, and possibly language additions. This entails a lot of writing of documentation, in effect a small book for each facet of D.
>
> There is much to be decided about how this could be best done. I will not pursue that here. But I do believe something approximately like this is the only way for D to start to win out when someone decides whether to use (e.g.) Go or D in a new situation, or even whether to use D or stay back in Python with all of its disadvantages. The complex cliff face of D needs some overtly navigated paths for all kinds of explorers.

I think this is a good approach. The beauty of D is that it can be a lot of different things to different people. Do you have any examples yet, as in "D for Python programmers"? E.g. loops:

Python:
for item in list:
  print "The item is %s" % item

D:
import std.stdio : writefln;
foreach(ref item; list) {
  writefln("The item is %s", item);
}