Skip to main content
deleted 451 characters in body
Source Link

You only need implementations of < and == as the rest can all be derived:

op shorthand for
a!=b not(a==b)
a<=b not(b<a)
a>b b<a
a>=b not(a<b)

Unlike C, you should have multiple implementations of < and ==:

operator operands implementation
== both same naïve
== mixed false if not in common range
< both unsigned naïve
< both signed invert sign bits then as per unsigned
< signed+unsigned true if first operand is negative or second operand exceeds max_signed
< unsigned+signed false if first operand exceeds max_signed or second operand is negative

For signed-operand operator unsigned-operand, the == and > operators should return false if the signed operand is negative or the unsigned operand exceeds signed_max; while the reverse applies to the < operator.

The < and > operators will need separate implementations for signed and unsigned.

Note that you don't need to implement !=, >= and <= because they're the logical inverses of ==, < and > respectively.

You only need implementations of < and == as the rest can all be derived:

op shorthand for
a!=b not(a==b)
a<=b not(b<a)
a>b b<a
a>=b not(a<b)

Unlike C, you should have multiple implementations of < and ==:

operator operands implementation
== both same naïve
== mixed false if not in common range
< both unsigned naïve
< both signed invert sign bits then as per unsigned
< signed+unsigned true if first operand is negative or second operand exceeds max_signed
< unsigned+signed false if first operand exceeds max_signed or second operand is negative

For signed-operand operator unsigned-operand, the == and > operators should return false if the signed operand is negative or the unsigned operand exceeds signed_max; while the reverse applies to the < operator.

The < and > operators will need separate implementations for signed and unsigned.

Note that you don't need to implement !=, >= and <= because they're the logical inverses of ==, < and > respectively.

You only need implementations of < and == as the rest can all be derived:

op shorthand for
a!=b not(a==b)
a<=b not(b<a)
a>b b<a
a>=b not(a<b)

Unlike C, you should have multiple implementations of < and ==:

operator operands implementation
== both same naïve
== mixed false if not in common range
< both unsigned naïve
< both signed invert sign bits then as per unsigned
< signed+unsigned true if first operand is negative or second operand exceeds max_signed
< unsigned+signed false if first operand exceeds max_signed or second operand is negative
consistently use `not` rather than `!` to describe operations.
Source Link

You only need implementations of < and == as the rest can all be derived:

op shorthand for
a!=b not(a==b)
a<=b !not(b<a)
a>b b<a
a>=b !not(a<b)

Unlike C, you should have multiple implementations of < and ==:

operator operands groupingimplementation
== both same naïve
== mixed false if not in common range
< both unsigned naïve
< both signed invert sign bits then as per unsigned
< signed+unsigned true if first operand is negative or second operand exceeds max_signed
< unsigned+signed false if first operand exceeds max_signed or second operand is negative

For signed-operand operator unsigned-operand, the == and > operators should return false if the signed operand is negative or the unsigned operand exceeds signed_max; while the reverse applies to the < operator.

The < and > operators will need separate implementations for signed and unsigned.

Note that you don't need to implement !=, >= and <= because they're the logical inverses of ==, < and > respectively.

You only need implementations of < and == as the rest can all be derived:

op shorthand for
a!=b not(a==b)
a<=b !(b<a)
a>b b<a
a>=b !(a<b)

Unlike C, you should have multiple implementations of < and ==:

operator operands grouping
== both same naïve
== mixed false if not in common range
< both unsigned naïve
< both signed invert sign bits then as per unsigned
< signed+unsigned true if first operand is negative or second operand exceeds max_signed
< unsigned+signed false if first operand exceeds max_signed or second operand is negative

For signed-operand operator unsigned-operand, the == and > operators should return false if the signed operand is negative or the unsigned operand exceeds signed_max; while the reverse applies to the < operator.

The < and > operators will need separate implementations for signed and unsigned.

Note that you don't need to implement !=, >= and <= because they're the logical inverses of ==, < and > respectively.

You only need implementations of < and == as the rest can all be derived:

op shorthand for
a!=b not(a==b)
a<=b not(b<a)
a>b b<a
a>=b not(a<b)

Unlike C, you should have multiple implementations of < and ==:

operator operands implementation
== both same naïve
== mixed false if not in common range
< both unsigned naïve
< both signed invert sign bits then as per unsigned
< signed+unsigned true if first operand is negative or second operand exceeds max_signed
< unsigned+signed false if first operand exceeds max_signed or second operand is negative

For signed-operand operator unsigned-operand, the == and > operators should return false if the signed operand is negative or the unsigned operand exceeds signed_max; while the reverse applies to the < operator.

The < and > operators will need separate implementations for signed and unsigned.

Note that you don't need to implement !=, >= and <= because they're the logical inverses of ==, < and > respectively.

added 11 characters in body
Source Link

The second is easy: in general you want both, but in practice it's less cumbersome to use a single type (unsigned) for storage and to implement separate implementations of operators for those cases where results differ, especially ==, !=, <, <=, >, >=, >>, / & %.

As for literals, I suggest copying what Go does: a numeric literal has its own notional type, but you can't declare a variable of this type. Instead, a literal is silently and implicitly converted to any numeric type (as long as it fits). If your language does type inference, then a numeric literal also has a preferred standard type. The compiler should perform all constant folding using "infinite precision" before using the results to generate code.

PS: having modulus apply on assignment means you actually need dual implementations of most arithmetic operators, one that traps on overflow, and one that ignores overflow (because it gets the right answer when later applying modulus). If you eventually get around implementing "arbitrary modulus", the target modulus needs to be included as a hidden third parameter to the non-trapping operators.

The second is easy: in general you want both, but in practice it's less cumbersome to use a single type for storage and to implement separate implementations of operators for those cases where results differ, especially ==, !=, <, <=, >, >=, >>, / & %.

As for literals, I suggest copying what Go does: a numeric literal has its own notional type, but you can't declare a variable of this type. Instead, a literal is silently and implicitly converted to any numeric type (as long as it fits). If your language does type inference, then a numeric literal also has a preferred standard type. The compiler should perform all constant folding using "infinite precision" before using the results to generate code.

The second is easy: in general you want both, but in practice it's less cumbersome to use a single type (unsigned) for storage and to implement separate implementations of operators for those cases where results differ, especially ==, !=, <, <=, >, >=, >>, / & %.

As for literals, I suggest copying what Go does: a numeric literal has its own notional type, but you can't declare a variable of this type. Instead, a literal is silently and implicitly converted to any numeric type (as long as it fits). If your language does type inference, then a numeric literal also has a preferred standard type. The compiler should perform all constant folding using "infinite precision" before using the results to generate code.

PS: having modulus apply on assignment means you actually need dual implementations of most arithmetic operators, one that traps on overflow, and one that ignores overflow (because it gets the right answer when later applying modulus). If you eventually get around implementing "arbitrary modulus", the target modulus needs to be included as a hidden third parameter to the non-trapping operators.

added 1267 characters in body
Source Link
Loading
deleted 39 characters in body
Source Link
Loading
Source Link
Loading