mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
Add appendix to spec which specifies JavaScript integer behavior.
Also update the `int` class documentation. Change-Id: I2de6c62aa9642c18134effa8187a12902d5f2259 Reviewed-on: https://dart-review.googlesource.com/58204 Commit-Queue: Lasse R.H. Nielsen <lrn@google.com> Reviewed-by: Leaf Petersen <leafp@google.com>
This commit is contained in:
parent
dfeaf79cef
commit
87131780cb
2 changed files with 117 additions and 62 deletions
|
@ -58,6 +58,8 @@
|
|||
% - Specify configurable imports.
|
||||
% - Specify the dynamic type of the Iterable/Future/Stream returned from
|
||||
% invocations of functions marked sync*/async/async*.
|
||||
% - Add appendix listing the major differences between 64-bit integers
|
||||
% and JavaScript integers.
|
||||
%
|
||||
% 1.15
|
||||
% - Change how language specification describes control flow.
|
||||
|
@ -10482,6 +10484,43 @@ Example: my\_favorite\_library.
|
|||
\end{itemize}
|
||||
}
|
||||
|
||||
\section*{Appendix: Integer Implementations}
|
||||
\LMLabel{integerImplementations}
|
||||
|
||||
\commentary{
|
||||
The \code{int} type represents integers.
|
||||
The specification is written with 64-bit two's complement integers as the
|
||||
intended implementation, but when Dart is compiled to JavaScript,
|
||||
the implementation of \code{int} will instead use the JavaScript
|
||||
number type.
|
||||
|
||||
This introduces a number of differencs:
|
||||
\begin{itemize}
|
||||
\item Valid values of JavaScript \code{int} are any
|
||||
IEEE-754 64-bit floating point number with no fractional part.
|
||||
This includes positive and negative {\em infinity},
|
||||
which can be reached by overflowing
|
||||
(integer division by zero is still not allowed).
|
||||
Otherwise valid integer literals (including any leading minus sign)
|
||||
that represent invalid JavaScript \code{int} values
|
||||
cannot be compiled to JavaScript.
|
||||
Operations on integers may lose precision since 64-bit floating point numbers
|
||||
are limited to 53 significant bits.
|
||||
\item JavaScript \code{int} instances also implement \code{double},
|
||||
and integer-valued \code{double} instances also implement \code{int}.
|
||||
The \code{int} and \code{double} class are still separate subclasses of the
|
||||
class \code{num}, but {\em instances} of either class that represent an integer,
|
||||
act as if they are actually instances of a common subclass implementing both
|
||||
\code{int} and \code{double}. Fractional numbers only implement \code{double}.
|
||||
\item Bitwise operations on integers (and, or, xor, negate and shifts)
|
||||
all truncate the operands to 32-bit values.
|
||||
\item The \code{identical} method cannot distinguish the values $0.0$ and $-0.0$,
|
||||
and it cannot recognize any {\em NaN} value as identical to itself.
|
||||
For efficiency, the \code{identical} operation uses the JavaScript \code{===}
|
||||
operator.
|
||||
\end{itemize}
|
||||
}
|
||||
|
||||
\end{document}
|
||||
|
||||
[Text after \end{document} is ignored, hence we do not need "%"]
|
||||
|
|
|
@ -5,30 +5,36 @@
|
|||
part of dart.core;
|
||||
|
||||
/**
|
||||
* An arbitrarily large integer.
|
||||
* An integer number.
|
||||
*
|
||||
* **Note:** When compiling to JavaScript, integers are
|
||||
* implemented as JavaScript numbers. When compiling to JavaScript,
|
||||
* integers are therefore restricted to 53 significant bits because
|
||||
* all JavaScript numbers are double-precision floating point
|
||||
* values. The behavior of the operators and methods in the [int]
|
||||
* The default implementation of `int` is 64-bit two's complement integers
|
||||
* with operations that wrap to that range on overflow.
|
||||
*
|
||||
* **Note:** When compiling to JavaScript, integers are restricted to valus
|
||||
* that can be represented exactly by double-precision floating point values.
|
||||
* The available integer values include all integers between -2^53 and 2^53,
|
||||
* and some integers with larger magnitude. That includes some integers larger
|
||||
* than 2^63.
|
||||
* The behavior of the operators and methods in the [int]
|
||||
* class therefore sometimes differs between the Dart VM and Dart code
|
||||
* compiled to JavaScript.
|
||||
* compiled to JavaScript. For example, the bitwise operators truncate their
|
||||
* operands to 32-bit integers when compiled to JavaScript.
|
||||
*
|
||||
* It is a compile-time error for a class to attempt to extend or implement int.
|
||||
* Classes cannot extend, implement, or mix in `int`.
|
||||
*/
|
||||
abstract class int extends num {
|
||||
/**
|
||||
* Returns the integer value of the given environment declaration [name].
|
||||
*
|
||||
* The result is the same as would be returned by:
|
||||
*
|
||||
* int.parse(const String.fromEnvironment(name, defaultValue: ""),
|
||||
* (_) => defaultValue)
|
||||
*
|
||||
* ```
|
||||
* int.tryParse(const String.fromEnvironment(name, defaultValue: ""))
|
||||
* ?? defaultValue
|
||||
* ```
|
||||
* Example:
|
||||
*
|
||||
* const int.fromEnvironment("defaultPort", defaultValue: 80)
|
||||
* ```
|
||||
* const int.fromEnvironment("defaultPort", defaultValue: 80)
|
||||
* ```
|
||||
*/
|
||||
// The .fromEnvironment() constructors are special in that we do not want
|
||||
// users to call them using "new". We prohibit that by giving them bodies
|
||||
|
@ -157,17 +163,18 @@ abstract class int extends num {
|
|||
*
|
||||
* To find the number of bits needed to store the value as a signed value,
|
||||
* add one, i.e. use `x.bitLength + 1`.
|
||||
* ```
|
||||
* x.bitLength == (-x-1).bitLength
|
||||
*
|
||||
* x.bitLength == (-x-1).bitLength
|
||||
*
|
||||
* 3.bitLength == 2; // 00000011
|
||||
* 2.bitLength == 2; // 00000010
|
||||
* 1.bitLength == 1; // 00000001
|
||||
* 0.bitLength == 0; // 00000000
|
||||
* (-1).bitLength == 0; // 11111111
|
||||
* (-2).bitLength == 1; // 11111110
|
||||
* (-3).bitLength == 2; // 11111101
|
||||
* (-4).bitLength == 2; // 11111100
|
||||
* 3.bitLength == 2; // 00000011
|
||||
* 2.bitLength == 2; // 00000010
|
||||
* 1.bitLength == 1; // 00000001
|
||||
* 0.bitLength == 0; // 00000000
|
||||
* (-1).bitLength == 0; // 11111111
|
||||
* (-2).bitLength == 1; // 11111110
|
||||
* (-3).bitLength == 2; // 11111101
|
||||
* (-4).bitLength == 2; // 11111100
|
||||
* ```
|
||||
*/
|
||||
int get bitLength;
|
||||
|
||||
|
@ -175,21 +182,22 @@ abstract class int extends num {
|
|||
* Returns the least significant [width] bits of this integer as a
|
||||
* non-negative number (i.e. unsigned representation). The returned value has
|
||||
* zeros in all bit positions higher than [width].
|
||||
*
|
||||
* (-1).toUnsigned(5) == 31 // 11111111 -> 00011111
|
||||
*
|
||||
* ```
|
||||
* (-1).toUnsigned(5) == 31 // 11111111 -> 00011111
|
||||
* ```
|
||||
* This operation can be used to simulate arithmetic from low level languages.
|
||||
* For example, to increment an 8 bit quantity:
|
||||
*
|
||||
* q = (q + 1).toUnsigned(8);
|
||||
*
|
||||
* ```
|
||||
* q = (q + 1).toUnsigned(8);
|
||||
* ```
|
||||
* `q` will count from `0` up to `255` and then wrap around to `0`.
|
||||
*
|
||||
* If the input fits in [width] bits without truncation, the result is the
|
||||
* same as the input. The minimum width needed to avoid truncation of `x` is
|
||||
* given by `x.bitLength`, i.e.
|
||||
*
|
||||
* x == x.toUnsigned(x.bitLength);
|
||||
* ```
|
||||
* x == x.toUnsigned(x.bitLength);
|
||||
* ```
|
||||
*/
|
||||
int toUnsigned(int width);
|
||||
|
||||
|
@ -199,24 +207,26 @@ abstract class int extends num {
|
|||
* to fit in [width] bits using an signed 2-s complement representation. The
|
||||
* returned value has the same bit value in all positions higher than [width].
|
||||
*
|
||||
* V--sign bit-V
|
||||
* 16.toSigned(5) == -16 // 00010000 -> 11110000
|
||||
* 239.toSigned(5) == 15 // 11101111 -> 00001111
|
||||
* ^ ^
|
||||
*
|
||||
* ```
|
||||
* V--sign bit-V
|
||||
* 16.toSigned(5) == -16 // 00010000 -> 11110000
|
||||
* 239.toSigned(5) == 15 // 11101111 -> 00001111
|
||||
* ^ ^
|
||||
* ```
|
||||
* This operation can be used to simulate arithmetic from low level languages.
|
||||
* For example, to increment an 8 bit signed quantity:
|
||||
*
|
||||
* q = (q + 1).toSigned(8);
|
||||
*
|
||||
* ```
|
||||
* q = (q + 1).toSigned(8);
|
||||
* ```
|
||||
* `q` will count from `0` up to `127`, wrap to `-128` and count back up to
|
||||
* `127`.
|
||||
*
|
||||
* If the input value fits in [width] bits without truncation, the result is
|
||||
* the same as the input. The minimum width needed to avoid truncation of `x`
|
||||
* is `x.bitLength + 1`, i.e.
|
||||
*
|
||||
* x == x.toSigned(x.bitLength + 1);
|
||||
* ```
|
||||
* x == x.toSigned(x.bitLength + 1);
|
||||
* ```
|
||||
*/
|
||||
int toSigned(int width);
|
||||
|
||||
|
@ -271,8 +281,8 @@ abstract class int extends num {
|
|||
* Returns a String-representation of this integer.
|
||||
*
|
||||
* The returned string is parsable by [parse].
|
||||
* For any `int` [:i:], it is guaranteed that
|
||||
* [:i == int.parse(i.toString()):].
|
||||
* For any `int` `i`, it is guaranteed that
|
||||
* `i == int.parse(i.toString())`.
|
||||
*/
|
||||
String toString();
|
||||
|
||||
|
@ -289,7 +299,7 @@ abstract class int extends num {
|
|||
/**
|
||||
* Parse [source] as a, possibly signed, integer literal and return its value.
|
||||
*
|
||||
* The [source] must be a non-empty sequence of base-[radix] digits,
|
||||
* The [source] must be either a non-empty sequence of base-[radix] digits,
|
||||
* optionally prefixed with a minus or plus sign ('-' or '+').
|
||||
*
|
||||
* The [radix] must be in the range 2..36. The digits used are
|
||||
|
@ -299,30 +309,36 @@ abstract class int extends num {
|
|||
*
|
||||
* If no [radix] is given then it defaults to 10. In this case, the [source]
|
||||
* digits may also start with `0x`, in which case the number is interpreted
|
||||
* as a hexadecimal literal, which effectively means that the `0x` is ignored
|
||||
* and the radix is instead set to 16.
|
||||
* as a hexadecimal integer literal,
|
||||
* When `int` is implemented by 64-bit signed integers,
|
||||
* hexadecimal integer literals may represent values larger than
|
||||
* 2<sup>63</sup>, in which case the value is parsed as if it is an
|
||||
* *unsigned* number, and the resulting value is the corresponding
|
||||
* signed integer value.
|
||||
*
|
||||
* For any int [:n:] and radix [:r:], it is guaranteed that
|
||||
* [:n == int.parse(n.toRadixString(r), radix: r):].
|
||||
* For any int `n` and valid radix `r`, it is guaranteed that
|
||||
* `n == int.parse(n.toRadixString(r), radix: r)`.
|
||||
*
|
||||
* If the [source] is not a valid integer literal, optionally prefixed by a
|
||||
* sign, the [onError] is called with the [source] as argument, and its return
|
||||
* value is used instead. If no [onError] is provided, a [FormatException]
|
||||
* is thrown.
|
||||
* If the [source] does not contain a valid integer literal,
|
||||
* optionally prefixed by a sign, a [FormatException] is thrown
|
||||
* (unless the deprecated [onError] parameter is used, see below).
|
||||
*
|
||||
* The [onError] handler can be chosen to return `null`. This is preferable
|
||||
* to to throwing and then immediately catching the [FormatException].
|
||||
* Instead of throwing and immediately catching the [FormatException],
|
||||
* instead use [tryParse] to handle a parsing error.
|
||||
* Example:
|
||||
*
|
||||
* var value = int.parse(text, onError: (source) => null);
|
||||
* if (value == null) ... handle the problem
|
||||
*
|
||||
* The [onError] function is only invoked if [source] is a [String]. It is
|
||||
* not invoked if the [source] is, for example, `null`.
|
||||
* ```dart
|
||||
* var value = int.tryParse(text);
|
||||
* if (value == null) ... handle the problem
|
||||
* ```
|
||||
*
|
||||
* The [onError] parameter is deprecated and will be removed.
|
||||
* Instead of `int.parse(string, onError: (string) { ... })`,
|
||||
* Instead of `int.parse(string, onError: (string) => ...)`,
|
||||
* you should use `int.tryParse(string) ?? (...)`.
|
||||
*
|
||||
* When source is not valid and [onError] is provided,
|
||||
* whenever a [FormatException] would be thrown,
|
||||
* [onError] is instead called with [source] as argument,
|
||||
* and the result of that call is returned by [parse].
|
||||
*/
|
||||
external static int parse(String source,
|
||||
{int radix, @deprecated int onError(String source)});
|
||||
|
|
Loading…
Reference in a new issue