Sign of the times

What would you do to improve the following?

func sign<T: SignedNumberType>(value: T) -> Int {
   return value == (0 as T) 
       ? 0 : (value > 0 ? 1 : -1)
}

or if you like it typed:

func sign<T: SignedNumberType>(value: T) -> T {
    return (value == (0 as T) 
        ? 0 : (value > 0 ? 1 : -1)) as T
}

Here’s what I call the Groffian Lapse In Judgement:

extension Bool: RawRepresentable {
  public typealias RawValue = Int
  public var rawValue: Int {return self ? 1 : 0}
  public init?(rawValue: Int) { self = rawValue == 1 }
}

func signbadTheSailor<
        T: protocol<SignedNumberType, IntegerLiteralConvertible>
        where T.IntegerLiteralType: SignedIntegerType
    > (value: T) -> T {
    let theSign = (value > 0).rawValue - (value < 0).rawValue
    let result: T.IntegerLiteralType = numericCast(theSign)
    return T(integerLiteral: result)
}

Thanks.

5 Comments

  • I don’t know who this person is, but I would ask them, “Who hurt you?”

  • Why? Why would you do this? Nesting ternary operators…? C’mon

  • *begins weeping*

  • In all seriousness though, what does better mean? Space? Readability? Performance? …All I’ve figured is that you *definitely* need T (womp womp womp)

  • Okay. Taking this seriously …

    Minimum: linebreak before each colon.

    Use an if … else if … return. Any compiler since, oh, 1980 will generate the same code. Any programmer since 1880 (before which nobody was born who could have taken up a programming language that could express either) would understand it at a glance as she would not a chained ternary.

    Consider that 1.0 + 3.0*2.7 – 9.1 almost never == 0.0. Create a generic (wiggly equal sign, opt-x on an en_US Mac keyboard — sorry, I’m on my iPad) operator which uses ==, but specialized for FloatingPointType by testing for proportional difference (lt) epsilon.

    (Avoiding trouble with XML tag delimiters.)

    I use an actual epsilon character because I’m fancy.

    Remember to make epsilon larger for Float than you’d prefer for Double. And avoid putting zero in the denominator, probably using a guard to test the nonzero operand for small-enough. Oh, and by the way, CGFloat is Float in 32-bit architecture, Double in 64. And CGRect, and …

    Contemplate that operands could be equal-enough while also (lt) or (gt). It doesn’t carry the postulate you probably assume that (gt), (eq), and (lt) partition the set of numbers. Test for equal-enough first.