Skip to content

A Ruby string prefers System::String over System::Boolean in overload resolution - #5

Merged
Largo merged 1 commit into
masterfrom
claude/awesome-feynman-17fb66
Sep 30, 2026
Merged

Largo merged 1 commit into
masterfrom
claude/awesome-feynman-17fb66

Conversation

@Largo

@Largo Largo commented Sep 30, 2026

Copy link
Copy Markdown
Owner

Follow-up to #4, which added the String-over-Byte[] rule.

Problem

System::IO::BinaryWriter.new(System::IO::MemoryStream.new).Write("abc")
# => System::Reflection::AmbiguousMatchException: Found multiple methods for 'Write':
#    Write(System::Boolean), Write(System::Byte[]), Write(System::Char), Write(System::String)

MutableString has explicit conversions to String, Byte[] and Char, and Converter.CanConvertFrom lets any argument convert to Boolean. All four are on narrowing level 2, and Write has no Object overload to catch the argument earlier. #4 settles String vs Byte[] and PreferConvert already settles String vs Char, but String vs Boolean still ends up Ambiguous in the DLR's GetPreferredParameter.

Change

RubyOverloadResolver.SelectBestConversionFor now prefers String over Boolean as well as over Byte[] for a MutableString argument. Neither bool nor byte[] has a default protocol conversion, so for a Ruby string a Boolean parameter is only reachable at level 2. The rule therefore only changes comparisons that used to be ambiguous.

These still resolve as before, because the rule only applies to a MutableString argument:

  • nil is still ambiguous (it goes through the separate nil branch).
  • Symbols are still ambiguous between String and Boolean.
  • Numbers and other objects still pick Boolean.
  • Inst.Bool in ClrConversions1 has a single overload, so it never gets here.

Tests

  • ClrOverloadSelection4 (new, registered in RubyTests.cs): F(String)/F(Boolean) with strings, true/false, 1, Object.new, nil and :foo, and BinaryWriter#Write with a string, a CLR string, a Boolean, a Byte[], a Char and nil.
  • OverloadResolution_Numeric1: new P rows (String/Boolean) and Q rows (the four Write overloads a Ruby string reaches).

This was not built locally (no .NET SDK on that machine), so this CI run is the first build and test run. The 4.0.0-preview1 release reproduces the bug. Every line of the new BinaryWriter test that doesn't depend on the fix already matches that release's output exactly.

Known edge case

For overloads like F(String, Double) / F(Boolean, Int32) called as ("s", 1), the second argument used to decide, and the string was silently passed as true. That call is now ambiguous. The Byte[] rule from #4 has the same effect.

Not covered here: a Ruby subclass of String (class S < String) still makes Write write true. The DLR doesn't find MutableString's conversion operators for the subclass's CLR type, so only Boolean applies at level 2. That's a conversion bug, not a tie, and is left for a separate change.

… resolution

Any argument converts to Boolean on narrowing level 2, the level of MutableString's
explicit conversions, so a Ruby string tied String and Boolean overloads:
System::IO::BinaryWriter#Write("abc") raised AmbiguousMatchException (Boolean, Byte[],
Char, String; Write has no Object overload). The String-over-Byte[] rule in
SelectBestConversionFor now covers Boolean too, and PreferConvert already orders
String over Char. nil, symbols and other non-string arguments resolve as before.
@Largo
Largo merged commit 7e13a27 into master Sep 30, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant