Search code examples
ddmd

Unexpected behaviour with string and std.file


I have the following block of code, which compiles cleanly on DMD v2.063.2

import std.stdio;
import std.string;
import std.file;

void main(string[] args)
{
    auto file = File("a_file.txt", "rb");

    string line;
    string source;

    while ((line = file.readln()) !is null)
    {
        source.append(line);
    }

    writeln("--- source: ---");
    writeln(source);
    writeln("---------------");
}

However, every time it is run, this error happens:

std.file.FileException@std/file.d(386): : No such file or directory
----------------
5   test                                0x000000010b955c9e void std.file.writeImpl(const(char[]), const(void[]), const(uint)) + 142
6   test                                0x000000010b955c08 void std.file.append(const(char[]), const(void[])) + 56
7   test                                0x000000010b92787e _Dmain + 174
8   test                                0x000000010b94330d extern (C) int rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).void runMain() + 33
9   test                                0x000000010b942e59 extern (C) int rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).void tryExec(scope void delegate()) + 45
10  test                                0x000000010b943359 extern (C) int rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).void runAll() + 61
11  test                                0x000000010b942e59 extern (C) int rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).void tryExec(scope void delegate()) + 45
12  test                                0x000000010b942e0d _d_run_main + 457
13  test                                0x000000010b942c3c main + 20
14  libdyld.dylib                       0x00007fff9a7de5fd start + 1
15  ???                                 0x0000000000000001 0x0 + 1
----------------

I was puzzled by the error, since the file existed and was clearly being opened. The error messages was completely misleading. I've managed to pinpoint the error to the line source.append(line); in the body of the while() loop.

It was when by chance I took a look at the documentation of the string type and found out that it does NOT have an append method. Then, looking at the documentation of std.file I find that there is a global append function. The the error message then kind of makes sense.

So it looks like the compiler is somehow managing to call std.file.append on the source string object (as we can observe in the exception call stack), thus causing this very tricky bug. How is this even possible? Can anyone shed some light on this problem?

Forgive me if I'm missing some basic point of the language here, I'm a beginner, but this seems to completely break the idea of type safety, no?


Solution

  • You're seeing UFCS in action. You may have not expected it, but I don't see how it breaks type safety. The exception message could use a mention of the file that couldn't be found, though. like "No such file or directory: filename.ext".