Kernel#Complex
Complex(arg, imag = nil, exception: true) Kernel#Complex builds a Complex number from numeric parts, or parses one out of a string. The result is always a Complex, even when the imaginary part is zero. The function form has been in Ruby since 1.0; the exception: keyword argument was added in Ruby 2.6.
What Complex() does
You can call Complex(...) from anywhere as a top-level function, and the same private method is reachable as Kernel#Complex on every object (because Kernel is mixed into Object). The accepted shapes are:
Complex(real, imag = nil, exception: true) # numeric path
Complex(string, exception: true) # string-parsing path
The second argument is the imaginary part. If you pass an existing Complex as the only argument, it is returned unchanged. With exception: false, an unparseable string returns nil instead of raising.
Accepted argument forms
Two numeric arguments (rectangular)
Two numbers give you a rectangular Complex:
Complex(1, 2) # => (1+2i)
Complex(0.0, 1.0) # => (0.0+1.0i)
Complex(Rational(1, 2), 3) # => ((1/2)+3i)
Mix Integer, Float, and Rational freely; the parts are stored with the precision you pass. This is equivalent to Complex.rect(real, imag).
One numeric argument
A single number is treated as the real part, with a zero imaginary part:
Complex(1) # => (1+0i)
Complex(-3.5) # => (-3.5+0i)
If you pass an existing Complex as the only argument, it is returned unchanged. This passthrough is worth knowing: it means Complex(some_complex) is cheap, and you can normalise “might be a number, might already be complex” inputs without a type check. It is a useful shortcut when you have a value that came from user input or a library that might return either a plain number or a complex number.
c = Complex(2, 3)
Complex(c) # => (2+3i)
The result is the same object you passed in, not a new copy, so equal? returns true and any frozen flags are preserved. That detail is rarely useful on its own, but it explains why chained calls like Complex(Complex(x, y).conj) allocate only one new object instead of two.
String argument (rectangular)
A string with a sign-separated real and imaginary part, ending in i, parses the same way. The real part comes first, then the imaginary part, and the trailing i is required to mark the value as imaginary:
Complex('1+2i') # => (1+2i)
Complex('-1-2i') # => (-1-2i)
Complex('1.5e2+2i') # => (150.0+2i)
Real-only and imaginary-only strings are also accepted. A bare number like '1' is treated as a real value, and a number with a trailing i (like '1i') is treated as a pure imaginary value. The trailing i is required for the imaginary form, since without it the parser assumes you meant a real number.
Complex('1') # => (1+0i)
Complex('1i') # => (0+1i)
Complex('-1i') # => (0-1i)
No spaces are allowed, and Ruby uses i, not j (Complex('1+2j') raises ArgumentError).
String argument (polar, rational only)
The @ separator is the polar form, with magnitude on the left and angle on the right, both as Rational substrings:
Complex('1/2@3/4') # magnitude 1/2, angle 3/4 rad
Complex('-1/2@-3/4')
The polar string form is restricted to rationals. A float magnitude like '1.5@0' does not parse through Kernel#Complex; use Complex.polar(1.5, 0) for that.
The exception: keyword argument
By default, Complex raises ArgumentError when it cannot convert the input. The exception: flag (Ruby 2.6+) makes it return nil instead:
Complex('not a number') # raises ArgumentError
Complex('not a number', exception: false) # => nil
Complex('1+2i', exception: false) # => (1+2i)
Two things to watch for:
TypeErroris not suppressed byexception: false.Complex(nil),Complex(1, 'two'), andComplex('1+2i', 3)all raiseTypeErrorregardless of the flag, because they fail C-level argument coercion before the conversion path runs.- You can’t use underscores inside strings.
Complex('1_000+2i')raisesArgumentError. The full Ruby parser accepts them in numeric literals; the C-level parser used here does not.
Complex() vs Complex.rect and Complex.polar
Three functions overlap, and the choice matters for performance and accepted input types.
| Call | Accepts | String parsing | Notes |
|---|---|---|---|
Complex() | numeric, string | yes | The most general form; only one with the exception: flag |
Complex.rect(real, imag) | numeric | no | Equivalent to two-arg Complex(real, imag) |
Complex.polar(r, theta) | numeric | no | theta in radians; float magnitudes are fine, unlike the polar string form |
For values you know at write time, the literal 1+2i is faster and clearer. Complex() earns its keep when the parts come from variables, user input, or string parsing.
Common errors and gotchas
A handful of forms that look like they should work, but do not:
Complex('1 + 2i') # ArgumentError — no spaces
Complex('1+2j') # ArgumentError — Ruby uses i, not j
Complex('1+2i', 3) # TypeError — cannot mix parsed string with extra arg
Complex('1', '2') # TypeError — only one string allowed
Complex(nil) # TypeError — exception: false does not help
Complex('1.5@0') # ArgumentError — float magnitude not allowed in polar string
Also note: Kernel#Complex is a private method on Object. It is mixed into every object, so calling it with an explicit receiver (like "hi".Complex(1, 2)) raises NoMethodError because the method is private. Stick to the bareword form Complex(...) to avoid this.
"hi".Complex(1, 2)
# NoMethodError: private method `Complex' called for "hi":String
Conclusion
Kernel#Complex is the right tool when you need to build a Complex from variables or parse one from a string. Use Complex.rect or Complex.polar for the numeric-only paths, and the literal 1+2i when the value is known up front. In input-handling code, pass exception: false so a malformed string returns nil instead of raising. Remember that TypeError is never suppressed by the flag, and that Kernel#Complex stays a private method on Object regardless of how you call it.
See also
- Kernel#Integer: the integer conversion cousin, same
exception: falsebehaviour added in 2.6 - Kernel#Rational — the substrate for
Kernel#Complex’s rational polar form - Kernel#Float — useful for the
parse_complexfallback chain in real-world input handlers