Skip to content

[API Proposal]: Make BigInteger implement IConvertible #62022

@paulirwin

Description

@paulirwin

Background and motivation

API proposal with motivation as a new take (with rationale) on #36264.

Currently, the following code fails because BigInteger does not implement IConvertible, even though its value is easily convertible to int (each line in example below ran in dotnet repl):

using System.Numerics;
var bi = new BigInteger(123);
Convert.ToInt32(bi) // fails
var t = typeof(int);
Convert.ChangeType(bi, t) // also fails

The error message of the first failure is:

System.InvalidCastException: Unable to cast object of type 'System.Numerics.BigInteger' to type 'System.IConvertible'.

In order to make runtime conversion to other integer (or even non-integer) values possible, BigInteger should implement IConvertible.

Rationale and use case: I have created a Lisp-based (and Scheme-based) interpreted/dynamic language on .NET called Lillisp. To implement Scheme's rational number types (i.e. 1/3), I am using the Rationals library, which implements the numerator and denominator as BigIntegers. This is useful for rational/integer division, such as (/ 3 4 5) which yields 3/20, where 3 and 20 are BigIntegers. Implementing the Scheme numerator and denominator functions is therefore trivial, they just return the BigInteger .Numerator and .Denominator properties of the Rational instance respectively. The problem is that the result of this call cannot be passed as-is to a method taking an int, for example. Lillisp has a cast function (aside: this should probably be renamed to convert or something) that takes a value and a runtime type and calls Convert.ChangeType, and I expected (cast (numerator (/ 3 4 5)) Int32) to yield the Int32 value 3, but instead it fails because BigInteger is not IConvertible. While I can add methods to explicitly convert a BigInteger to other types, or implement dynamic casting via IL Emit, it would be nice to be able to do the runtime conversion in the same way that other integer types can be done. The BigInteger type already has explicit cast operators for most if not all of the IConvertible destination types, so this would be a natural fit to make BigInteger act like other integer types. This sounds similar to the Powershell language concerns of using BigInteger in #36264.

API Proposal

namespace System.Numerics
{
    // some attributes...
    public readonly struct BigInteger : ISpanFormattable, IComparable, IComparable<BigInteger>, IEquatable<BigInteger>, IConvertible
    {
        // ... implement IConvertible members
    }
}

The IConvertible members could possibly just delegate to the explicit cast operators that already exist on BigInteger.

API Usage

var bi = new BigInteger(123);
var i = Convert.ToInt32(bi);
// or
var ci = Convert.ChangeType(bi, typeof(int));

Alternative Designs

Unsure of what alternatives there could be to this change.

Risks

Adding an interface to BigInteger could be considered a breaking change.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions