(U)Int0, part 3(?)

I've posted about this before. I have a gist of a new version.

I also added the XCTest file I used, going through every official member according to Apple's Standard Library web pages. You can see that I tried separating the methods that have default implementations to the end of the file. The compilation control is still permitting the code because some of that default code isn't compatible. You can see explanations in the comments of the optional methods that I did not move to the end block (or moved there then moved back before uploading).

Some of the problems were standard library code that assumed the value 1 (or -1) was available. Or that certain unary operations ended up with an output value distinct from the input value. Besides those, the code should work, except for division and open Range (needed for random).

I already added a new bug based on my discoveries. If you have debug access to the Standard Library, maybe you could find other assumptions (or proof that a zero-width integer is a bad idea).

1 Like

Int0 is not a valid FixedWidthInteger type. In particular, as discussed in one of the earlier threads, it violates the constraint on bitWidth:

A signed, fixed-width integer type can represent values from -(2 ** (bitWidth - 1)) through (2 ** (bitWidth - 1)) - 1.

Due to this constraint, the smallest possible type conforming to FixedWidthInteger and SignedInteger would be Int1, with two values, 0 and -1. This is not an especially useful type, since one of its two values traps under almost any arithmetic operation, and the other one is zero, but I believe that it can conform.

UInt0 doesn't run afoul of the constraint discussed above; it should have exactly one value, which is zero.

Neither of these types has the value 1, as you note, which breaks some default implementations. I'm pretty OK with that, because both of these types are weird and not generally useful, so requiring them to provide their own implementations of these requirements is not surprising. Ideally the default implementations would work no matter what, but in practice we'll end up with a if bitWidth == 0 { // UInt0 implementation } check on many of them, and that's extra complexity for little real benefit. Feel free to post PRs, however, and we can discuss there.

If you have debug access to the Standard Library

I'm confused. Everyone has debug access to the standard library. What do you mean by this?

One note on your overrides:

public static prefix func ~(x: UInt0) -> UInt0 {
    // Overrule the default implementation from FixedWidthInteger, since
    // that uses a value of 1, which this type doesn't support.
    return x
}

It's not obvious that ~ shouldn't just fatalError. It's very reasonable to say that the way you define this operation for general integers is -x - 1, which would always trap. There's a bunch of weird gotchas like this around these edge-case types.

I know this is threatening to get into the weeds, but flipping all 0 bits of a 0 bit integer is definitely 0, not -1. If you want to define it arithmetically, I think it's trunc(-BigInt(x) - 1, N), since you need a rule that produces a positive number for "regular" UInts too.

6 Likes

I'm running this code on Xcode, with a regular library target. It doesn't include the ability to breakpoint into the Standard Library code (by default, or at all, AFAIK). I need to do that to see where I could suggest bug fixes (or give up).

I do have a local copy of the GItHub repository for Swift; that's how I knew of upcoming default implementations for +=, -=, and multiplyFullWidth. I would have to figure out how to build a copy of the Swift compiler from the repo and step into it for debugging.

./utils/build-script -h will give you a summary of build options. ./utils/build-script -r --debug-swift-stdlib is a decent choice for standard library debugging.

Terms of Service

Privacy Policy

Cookie Policy