Skip to content

Conversation

Poita
Copy link
Contributor

@Poita Poita commented Jan 27, 2014

The function just had sloppy constraints while assuming it was a string. This fixes it up and adds some basic unit tests.

https://d.puremagic.com/issues/show_bug.cgi?id=11945

{
import std.exception : errnoEnforce;

alias ElementEncodingType!A C;
static assert(!is(C == void));
if (writeme[0].sizeof == 1 && orientation <= 0)
static if (isSomeString!A && C.sizeof == 1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this line and the two above could be better expressed as:

static if (is(Unqual!(ElementEncodingType!A) == char))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It also has to be a string type for the code to work. Just having a element type of const(char) is not enough (that's the cause of the bug in the first place).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No range should have an element type of char, they should always be dchar (e.g. std.array.front returns dchar for all strings). I suppose it's still technically possible to write, and so could erroneously appear in third-party code.

A better check could also be:

static if (is(A : const(char[])))

edit:

That said, this module is littered with bad code. In particular, issuing one write call per code point is probably terribly slow.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly, there's nothing stopping a user from writing a range of char (an ASCII string for example), so I don't think that's a good approach.

I don't believe is(A : const(char[])) is correct either. That checks if A implicitly converts to const(char[]), so, for example, Foo below would pass the check, but ptr would not be a const(char)* and the function would fail or have unexpected behaviour.

struct Foo
{
    const(char[]) str;
    alias str this;
    @property Foo* ptr() { return &this; }
}

I believe what I have is correct.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly, there's nothing stopping a user from writing a range of char (an ASCII string for example), so I don't think that's a good approach.

Yes, I acknowledge that it's technically possible, but as I said, it would be wrong code. In a range context, ASCII must be represented with ubyte.

I don't believe is(A : const(char[])) is correct either. That checks if A implicitly converts to const(char[]), so, for example, Foo below would pass the check, but ptr would not be a const(char)* and the function would fail or have unexpected behaviour.

Yes, AliasThis tends to subtly break generic constraints. We need a better assortment of standard traits to alleviate the need for deceptive is(T : U)-style checks.

I believe what I have is correct.

I never said it wasn't; the problem is that it's a round-about way of expressing it.

@JakobOvrum
Copy link
Contributor

This PR prompted me to have a look at std.stdio, and there's a lot of awful code in there... oh well, hopefully std.io will supersede is soon.

@Poita
Copy link
Contributor Author

Poita commented Feb 6, 2014

Any remaining issues that need addressing?

void put(A)(A writeme)
if (is(ElementType!A : const(dchar)) &&
isInputRange!A &&
!isInfinite!A)
{
import std.exception : errnoEnforce;

alias ElementEncodingType!A C;
static assert(!is(C == void));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this test is useless? We already have is(ElementType!A : const(dchar). Speaking of which, isn't that const also useless? Also, style nitpick, but can we put the isInputRange test before the ElementType test in the restraints? It just seems it would make more sense that way.

@monarchdodra
Copy link
Collaborator

Sorry for not reviewing sooner. How about:

        {
            import std.exception : errnoEnforce;

            alias ElementEncodingType!A C;
            static assert(!is(C == void));
            static if (isSomeString!A && C.sizeof == 1)
            {
                if (orientation <= 0)
                {
                    //file.write(writeme); causes infinite recursion!!!
                    //file.rawWrite(writeme);
                    auto result =
                        .fwrite(writeme.ptr, C.sizeof, writeme.length, fps);
                    if (result != writeme.length) errnoEnforce(0);
                    return; //RETURN HERE
                }
            }
            //NO ELSE HERE

            // put each character in turn
            foreach (dchar c; writeme)
                put(c);
        }

It avoids duplicating the else branch.

Other than my style nits, the root issue seems correctly fixed to me. Address and rebase, and I'll pull.

@Poita
Copy link
Contributor Author

Poita commented Feb 13, 2014

Done.

The function just had sloppy constraints while assuming it was a string. This fixes it up and adds some basic unit tests.

https://d.puremagic.com/issues/show_bug.cgi?id=11945
@ghost
Copy link

ghost commented Feb 15, 2014

Auto-merge toggled on

ghost pushed a commit that referenced this pull request Feb 15, 2014
Fix Issue 11945 - LockingTextWriter.put
@ghost ghost merged commit 2b558a9 into dlang:master Feb 15, 2014
@CyberShadow
Copy link
Member

This pull request introduced a regression:
https://d.puremagic.com/issues/show_bug.cgi?id=12375

@WalterBright
Copy link
Member

@Poita can you please look into the regression https://issues.dlang.org/show_bug.cgi?id=12375 ?

@Poita
Copy link
Contributor Author

Poita commented Jun 21, 2014

Looks like it has already been fixed as per @9rnsr's comment. Apologies for introducing it!

This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants