February 06, 2012
On 02/06/2012 09:11 PM, HansBKK wrote:
> On Friday, 20 January 2012 at 20:59:57 UTC, Denis Shelomovskij wrote:
>> But with a mistake: there are 15 delimiters in 16 element array
>> (printing/join result), not 16.
>
> That is truly sad - not only that you counted the commas, but publicly
> admitted it 8-)

That is truly sad - not only that you thought counting of commas was required to reach Denis' conclusion, but publicly admitted it. :o)
February 06, 2012
On Mon, Feb 06, 2012 at 09:11:35PM +0100, HansBKK wrote:
> On Friday, 20 January 2012 at 20:59:57 UTC, Denis Shelomovskij wrote:
> >But with a mistake: there are 15 delimiters in 16 element array
> >(printing/join result), not 16.
> 
> That is truly sad - not only that you counted the commas, but publicly admitted it 8-)

More Javascript WATs:

	[]+1	// "1" (a string, not a number)
	[]-1	// -1 (a number, not a string... WAT?)

	{}+1	// 1 (a number, not a string... huh?!)

	[]+"a"	// "a" (weird, but OK)
	{}+"a"	// NaN (WAT?)

Even worse:

	"a"+[]	// "a" (weird, but OK, consistent with []+"a")
	"a"+{}	// "a[object Object]" (WAT? inconsistent with {}+"a")


T

-- 
If it's green, it's biology, If it stinks, it's chemistry, If it has numbers it's math, If it doesn't work, it's technology.
February 07, 2012
OK, so this thread was supposed to be about WATs in D. Today I found one.

	std.stdio.File != std.stream.File

which means you can't assign stdin to InputStream.

Yes I know, you need to import cstream and use cstream.din instead, but this is very counterintuitive to a newcomer. It certainly elicited a WAT from me today when I first ran into this schizophrenic split between std.stdio (which is pretty much used in every D code example I've seen, which gives the impression that it's the "native" and "default" thing to use) and std.stream (which one would expect should naturally extend the functionality of std.stdio, but it doesn't).


T

-- 
The best compiler is between your ears. -- Michael Abrash
February 07, 2012
On Monday, February 06, 2012 17:13:28 H. S. Teoh wrote:
> OK, so this thread was supposed to be about WATs in D. Today I found one.
> 
> 	std.stdio.File != std.stream.File
> 
> which means you can't assign stdin to InputStream.
> 
> Yes I know, you need to import cstream and use cstream.din instead, but this is very counterintuitive to a newcomer. It certainly elicited a WAT from me today when I first ran into this schizophrenic split between std.stdio (which is pretty much used in every D code example I've seen, which gives the impression that it's the "native" and "default" thing to use) and std.stream (which one would expect should naturally extend the functionality of std.stdio, but it doesn't).

I guess that it depends on how you think or what you're used to. I wouldn't necessarily expect std.stream to be related to std.stdio at all. Certainly. in C++, stream-based and non-stream-based I/O isn't related at all (or if it is, it's an implementation detail). So, my general expectation is that they're completely separate, though I suppose that they don't _have_ to be designed that way.

Given that std.stream has its own File type, that would make it pretty obvious that the File from std.stdio would not work with std.stream. But I guess that you could see a function taking File in std.stream without having read enough of std.stream's documentation to realize that it had its own File type.

- Jonathan M Davis
February 07, 2012
On Mon, Feb 06, 2012 at 05:18:14PM -0800, Jonathan M Davis wrote:
> On Monday, February 06, 2012 17:13:28 H. S. Teoh wrote:
> > OK, so this thread was supposed to be about WATs in D. Today I found one.
> > 
> > 	std.stdio.File != std.stream.File
> > 
> > which means you can't assign stdin to InputStream.
> > 
> > Yes I know, you need to import cstream and use cstream.din instead, but this is very counterintuitive to a newcomer. It certainly elicited a WAT from me today when I first ran into this schizophrenic split between std.stdio (which is pretty much used in every D code example I've seen, which gives the impression that it's the "native" and "default" thing to use) and std.stream (which one would expect should naturally extend the functionality of std.stdio, but it doesn't).
> 
> I guess that it depends on how you think or what you're used to. I wouldn't necessarily expect std.stream to be related to std.stdio at all. Certainly. in C++, stream-based and non-stream-based I/O isn't related at all (or if it is, it's an implementation detail). So, my general expectation is that they're completely separate, though I suppose that they don't _have_ to be designed that way.

The thing is, coming from a Linux background, I've become accustomed to the "everything is a file" concept, which entails "file == stream". So I found it very strange to discover that this is not true in D, at least as far as std.stdio is concerned.


> Given that std.stream has its own File type, that would make it pretty obvious that the File from std.stdio would not work with std.stream. But I guess that you could see a function taking File in std.stream without having read enough of std.stream's documentation to realize that it had its own File type.
[...]

I certainly did not realize this, since the docs refer to "File" rather than "std.stream.File" or "std.stdio.File" explicitly.

But even after I realized there were two different File types, it took me yet another while to figure out how to bridge them with std.cstream. This is one of those things that *really* needs good docs for newbies, because it's a point of confusion to the uninitiated that needs to be explained.

On another note, I find this divide between std.stream and std.stdio quite jarring. The C++ model is to use <iostream> by default, and optionally provide <cstdio> to those who prefer it. This, I find, makes sense, because streams are a much more powerful concept that subsumes the concept of a file, and having it as default makes sense. Having <cstdio> as an option is merely a concession for C programmers who migrated to C++ (and I'm one of them who still hold on to cstdio over iostream) -- so it's understandable that the two cannot be freely intermixed.

In D, however, I did not expect this stream/stdio divide to exist, though I suppose the name "std.stdio" is a kind of giveaway. In any case, std.stdio is used all over the place in D docs and tutorials, besides write/writeln() being a pet example motivating variadic templates, so it seems to hold the equivalent place to <iostream> in C++. As such, I found it strange that this divide between streams and stdio files still persists in D. I would have thought that D should have integrated the two seamlessly into a single subsystem (or otherwise redesigned it in a more logical fashion), rather than perpetuating the schizophrenic divide inherited from C/C++.


T

-- 
Маленькие детки - маленькие бедки.
February 07, 2012
On Monday, February 06, 2012 21:49:23 H. S. Teoh wrote:
> On another note, I find this divide between std.stream and std.stdio quite jarring. The C++ model is to use <iostream> by default, and optionally provide <cstdio> to those who prefer it. This, I find, makes sense, because streams are a much more powerful concept that subsumes the concept of a file, and having it as default makes sense. Having <cstdio> as an option is merely a concession for C programmers who migrated to C++ (and I'm one of them who still hold on to cstdio over iostream) -- so it's understandable that the two cannot be freely intermixed.

In my experience, most C++ programmers ignore streams for basic I/O, if not in general. They're nice for some basic stuff and for object oriented stuff, but as soon as you need formatting, they're a pain. So, for the most part, printf gets used. I think that about the only place that I see streams used much is binary streams which take advantage of an object knowing how to write and read itself to and and from a stream. But even that's rare in my experience. I'm sure that it depends on the programmers though.

> In D, however, I did not expect this stream/stdio divide to exist, though I suppose the name "std.stdio" is a kind of giveaway. In any case, std.stdio is used all over the place in D docs and tutorials, besides write/writeln() being a pet example motivating variadic templates, so it seems to hold the equivalent place to <iostream> in C++. As such, I found it strange that this divide between streams and stdio files still persists in D. I would have thought that D should have integrated the two seamlessly into a single subsystem (or otherwise redesigned it in a more logical fashion), rather than perpetuating the schizophrenic divide inherited from C/C++.

You end up with pretty much the same thing in C# and Java. println and its friends are what's used most frequently (though it works better in D, C#, and Java than it does in C++, thanks to toString), though streams do get used for some stuff - usually not text though. It probably varies a bit from programmer to programmer though.

Regardless, I wouldn't really consider a file to be specific to either the stdio approach or streams. If anything, I find it bizarre that std.stream uses the term File for a stream. That seems to me to be like making a container into a range or an iterator, which really doesn't make sense. You have a range _over_ a container, not a container which is a range. One of the reasons that dealing with dynamic arrays in D can be so confusing is that they're ranges and people think that they're containers (though they really aren't, since they don't own their memory). Mixing the concept of file and stream seems like a bad idea. But it's probably just a case of a poorly named type.

In any case, std.stream is rather old and outdated and will be replaced at some point with a range-based API. And its replacement may interact with std.stdio better.

- Jonathan M Davis
February 07, 2012
On Mon, Feb 06, 2012 at 10:02:15PM -0800, Jonathan M Davis wrote:
> On Monday, February 06, 2012 21:49:23 H. S. Teoh wrote:
[...]
> In my experience, most C++ programmers ignore streams for basic I/O, if not in general. They're nice for some basic stuff and for object oriented stuff, but as soon as you need formatting, they're a pain. So, for the most part, printf gets used. I think that about the only place that I see streams used much is binary streams which take advantage of an object knowing how to write and read itself to and and from a stream. But even that's rare in my experience. I'm sure that it depends on the programmers though.

I don't see what's the discrepancy between formatting and streams. As far as I'm concerned, writeln() is essentially taking a bunch of objects, converting them to string representations, and writing said strings sequentially to some output channel (i.e., output stream).


[...]
> You end up with pretty much the same thing in C# and Java. println and its friends are what's used most frequently (though it works better in D, C#, and Java than it does in C++, thanks to toString), though streams do get used for some stuff - usually not text though. It probably varies a bit from programmer to programmer though.

And println/writeln is essentially writing to an output stream. It can be a file, a socket, a pipe, whatever. The functionality of a stream is all that's needed to implement it.


> Regardless, I wouldn't really consider a file to be specific to either the stdio approach or streams. If anything, I find it bizarre that std.stream uses the term File for a stream. That seems to me to be like making a container into a range or an iterator, which really doesn't make sense. You have a range _over_ a container, not a container which is a range. One of the reasons that dealing with dynamic arrays in D can be so confusing is that they're ranges and people think that they're containers (though they really aren't, since they don't own their memory). Mixing the concept of file and stream seems like a bad idea. But it's probably just a case of a poorly named type.

To me, most file operations are essentially treating them as streams. Reading a text file, whether it's char by char or line by line, is essentially reading from an input stream. The program then does some processing, and writes out some other data, be it text or binary or whatever, but it's mostly just a series of sequential writes. So it's an output stream.

Of course, files have more operations than just I/O streams; sometimes you do need seeking to some offset, and read/write stuff in non-sequential order. But usually this entails very specific file structures (e.g., using B-trees for databases, etc.). Most of the time it's just stream in, stream out.

The advantage of using streams is that your code can then operate on more than just files. It can work with sockets and pipes (that cannot support random access), string buffers, procedural data generators and consumers, etc.. Files are just a small subset of what the code can actually be used for.

In my mind, the D I/O system ought to be designed around this general concept. Files are just a specific instance of a stream (or range or what-have-you) that happens to have random-access operations, just as arrays just happen to be ranges with random-access operations, but ranges cover so much more.

In fact, functions like writeln() really ought to be completely generic as to where the output is sent. One should be able to, for example, write to a char buffer, or even to a char consumer function or object. Similarly, things like readln() or byLine() should be able to work with anything that behaves like a sequential source of characters: console, files, sockets, strings, functions or objects that spit out chars, etc.. Couple this with buffers (which are themselves sources/sinks, that just happen to have random-access for a limited range), and you've pretty much covered 90% of what files are generally used for.

The other 10% involve complicated file structures that will require hand-coding anyway, so it is sufficient for the actual File class to have extra methods for random access, and the user can code up the rest.

Code that need just a data source and/or a data sink shouldn't need to be unnecessarily limited to files. Imagine if std.regex can work directly with files. Or sockets. With no additional code save opening the file/setting up the socket. Or procedurally generated strings, without needing any intermediate buffers.


> In any case, std.stream is rather old and outdated and will be replaced at some point with a range-based API. And its replacement may interact with std.stdio better.
[...]

Yikes! So I should just avoid using it altogether then? How come it's not marked deprecated?


T

-- 
Which is worse: ignorance or apathy? Who knows? Who cares? -- Erich Schubert
February 07, 2012
On Monday, February 06, 2012 23:01:06 H. S. Teoh wrote:
> On Mon, Feb 06, 2012 at 10:02:15PM -0800, Jonathan M Davis wrote:
> > On Monday, February 06, 2012 21:49:23 H. S. Teoh wrote:
> [...]
> 
> > In my experience, most C++ programmers ignore streams for basic I/O, if not in general. They're nice for some basic stuff and for object oriented stuff, but as soon as you need formatting, they're a pain. So, for the most part, printf gets used. I think that about the only place that I see streams used much is binary streams which take advantage of an object knowing how to write and read itself to and and from a stream. But even that's rare in my experience. I'm sure that it depends on the programmers though.
> 
> I don't see what's the discrepancy between formatting and streams. As far as I'm concerned, writeln() is essentially taking a bunch of objects, converting them to string representations, and writing said strings sequentially to some output channel (i.e., output stream).

In C++, you end up with stuff like

cout << "point: [" << x << ", " << y "]" << endl;

That's already much uglier than

printf("point: [%f, %f]\n", x, y);

But what if you want to do something like %02f? With printf, that's easy:

printf("point: [%02f, %02f]\n", x, y);

With streams, it's hideous. I'd have to go look it up to give you an example. It involves setting flags in the stream and the like, and it's horrible. In my experience, no one uses it.

> [...]
> 
> > You end up with pretty much the same thing in C# and Java. println and its friends are what's used most frequently (though it works better in D, C#, and Java than it does in C++, thanks to toString), though streams do get used for some stuff - usually not text though. It probably varies a bit from programmer to programmer though.
> 
> And println/writeln is essentially writing to an output stream. It can be a file, a socket, a pipe, whatever. The functionality of a stream is all that's needed to implement it.
> 
> > Regardless, I wouldn't really consider a file to be specific to either the stdio approach or streams. If anything, I find it bizarre that std.stream uses the term File for a stream. That seems to me to be like making a container into a range or an iterator, which really doesn't make sense. You have a range _over_ a container, not a container which is a range. One of the reasons that dealing with dynamic arrays in D can be so confusing is that they're ranges and people think that they're containers (though they really aren't, since they don't own their memory). Mixing the concept of file and stream seems like a bad idea. But it's probably just a case of a poorly named type.
>
> [snip]

The long term plan is to create a std.stream which then provides a range-based interface for streams. Then you can do with it whatever you can do with any input stream - though there's still a lot that you would lose out on, since it can't be a forward range. Exactly how that will interact with std.stdio, I don't know. That will depend on the API that's finally decided up.

Regardless, my point was that while it might make sense to have a stream over a file, it doesn't make sense for a stream to _be_ a file, any more than it makes sense for a container to _be_ a range. You have a range over the container. The container itself isn't a range. So, std.stream's File type is poorly named IMHO. But it's going away in the long run, so it ultimately doesn't really matter what it was named.

> > In any case, std.stream is rather old and outdated and will be replaced at some point with a range-based API. And its replacement may interact with std.stdio better.
> 
> [...]
> 
> Yikes! So I should just avoid using it altogether then? How come it's not marked deprecated?

Because it doesn't have a replacement yet. The replacement has been discussed on some level, but no one has fleshed it out and implemented it yet. Steven Schveighoffer's rewrite of std.stdio may start that ball rolling. I don't know. What it really needs is a champion to take on the effort of leading the discussion, implementing it, and pushing it through the review process. No one has really stepped up to do that yet.

It's like std.xml. You can use it, but it's not going to be around in the long term, and we don't have a replacement for it yet. We're just certain that the current version is unacceptable and needs to be replaced. It would probably be a good idea to put a warning of some kind in the documentation, but for the moment, it's not going away.

- Jonathan M Davis
February 07, 2012
On 02/07/2012 06:49 AM, H. S. Teoh wrote:
> ....
>
> In D, however, I did not expect this stream/stdio divide to exist,
> though I suppose the name "std.stdio" is a kind of giveaway. In any
> case, std.stdio is used all over the place in D docs and tutorials,
> besides write/writeln() being a pet example motivating variadic
> templates, so it seems to hold the equivalent place to<iostream>  in
> C++. As such, I found it strange that this divide between streams and
> stdio files still persists in D. I would have thought that D should have
> integrated the two seamlessly into a single subsystem (or otherwise
> redesigned it in a more logical fashion), rather than perpetuating the
> schizophrenic divide inherited from C/C++.
>
>
> T
>

To be exact, your comparison is between Phobos/STL, not D/C++.
February 07, 2012
On 20/01/2012 20:59, Denis Shelomovskij wrote:
> 20.01.2012 19:40, Robert Clipsham пишет:
>> Just came across this amusing 4 minute video:
>>
>> https://www.destroyallsoftware.com/talks/wat
>>
>
> Good talk!
> But with a mistake: there are 15 delimiters in 16 element array (printing/join result),
> not 16.

I'm guessing that Gary really did work this all out beforehand, but claimed there are 16 as he thought it would amaze people more if they didn't know what "Array" and "join" really mean.

Stewart.