-
Notifications
You must be signed in to change notification settings - Fork 66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ValueTuple.Equals issue #320
Comments
Very interesting. For reference, here's the original C# code, the IL that it compiled to, and the C# that it decompiles to: static void Main()
{
(double, float) t1 = (1d, 2f);
(int, int) t2 = (1, 2);
Console.WriteLine(t1 == t2);
}
private static void Main()
{
ValueTuple<double, float> valueTuple = new ValueTuple<double, float>(1.0, 2f);
ValueTuple<int, int> valueTuple2 = new ValueTuple<int, int>(1, 2);
ValueTuple<double, float> valueTuple3 = valueTuple;
ValueTuple<int, int> valueTuple4 = valueTuple2;
Console.WriteLine(valueTuple3.Item1 == (double)valueTuple4.Item1 && valueTuple3.Item2 == (float)valueTuple4.Item2);
} Not really sure why it's copying the tuples before it compares them, but whatever. ¯\_(ツ)_/¯ Interestingly, you can use the Sub Main()
Dim t1 As (Double, Single) = (1.0R, 2.0F)
Dim t2 As (Integer, Integer) = (1, 2)
Console.WriteLine(t1.Equals(t2))
End Sub
And for completeness, here's the C# code that the VB code decompiles to: [STAThread]
public static void Main()
{
ValueTuple<double, float> valueTuple = new ValueTuple<double, float>(1.0, 2f);
ValueTuple<int, int> valueTuple2 = new ValueTuple<int, int>(1, 2);
ValueTuple<int, int> valueTuple3 = valueTuple2;
Console.WriteLine(valueTuple.Equals(new ValueTuple<double, float>((double)valueTuple3.Item1, (float)valueTuple3.Item2)));
} |
@reduckted |
The Dim t As Tuple(Of Double, Single)
Console.WriteLine(t = t)
~~~~~ ' Operator '=' is not defined for types 'Tuple(Of Double, Single)' and 'Tuple(Of Double, Single)'. In fact, take your original code, and compare Dim t1 As (Double, Single) = (1.0R, 2.0F)
Console.WriteLine(t1 = t1)
~~~~~~~ ' Operator '=' is not defined for types '(Double, Single)' and '(Double, Single)'. So the issue isn't that you can't compare different types of Perhaps someone with more knowledge of the compiler could explain how it handles |
The comparison of |
I think we can't copy c#'s implementation of this feature to VB directly. Because the equality and the inequality compare operators are special in VB. For example, |
@reduckted The VB ' Compile with /optioncompare:text
Dim a As (Object, String) = (Nothing, "ABC")
Dim b As (String, String) = ("", "aBc")
MsgBox(a = b) ' The output should be True. Because a.GetType.GenericTypeArguments.Length = b.GetType.GenericTypeArguments.Length AndAlso Nothing = "" AndAlso "ABC" = "aBc". C# (Object, String) a = (null, "ABC");
(String, String) b = ("", "ABC");
Console.WriteLine(a == b); // The output should be False. Because !a.GetType().Equals(b.GetType()) . |
@reduckted @Berrysoft @Nukepayload2 |
I've found a related LDM note. https://github.com/dotnet/vblang/blob/master/meetings/2018/vbldm-notes-2018.02.28.md |
@reduckted @Berrysoft @Nukepayload2 @srivatsn @migueldeicaza |
The extra work in |
@Nukepayload2 |
@MohammadHamdyGhanem Option Strict Off
Option Compare Text
Module Program
Sub Main(args As String())
Dim a = (1, "ABC", Nothing)
Dim b = ("1", "abc", "")
Dim tupleEquals = a.Equals(b)
Dim vbEquality = a.Item1 = b.Item1 AndAlso a.Item2 = b.Item2 AndAlso a.Item3 = b.Item3
Console.WriteLine(tupleEquals)
Console.WriteLine(vbEquality)
End Sub
End Module Decompiled: Imports Microsoft.VisualBasic.CompilerServices
Imports System.Runtime.CompilerServices
Friend Module Program
<STAThread>
Public Sub Main(args As String())
Dim valueTuple As ValueTuple(Of Integer, String, Object) = New ValueTuple(Of Integer, String, Object)(1, "ABC", Nothing)
Dim valueTuple1 As ValueTuple(Of String, String, String) = New ValueTuple(Of String, String, String)("1", "abc", "")
Dim flag As Boolean = valueTuple.Equals(valueTuple1)
Dim obj As Object = If(CDbl(valueTuple.Item1) <> Conversions.ToDouble(valueTuple1.Item1) OrElse EmbeddedOperators.CompareString(valueTuple.Item2, valueTuple1.Item2, True) <> 0, False, Conversions.ToBoolean(Operators.CompareObjectEqual(valueTuple.Item3, valueTuple1.Item3, True)))
Console.WriteLine(flag)
Console.WriteLine(RuntimeHelpers.GetObjectValue(obj))
End Sub
End Module |
Tuple equality was not initially added for value tuples, because there are some gnarly corners. Check out the Support for == and != for ValueTuple. I recall gnarly corners, but the resulting proposal is rather clean. I'd love to see us work together on a proposal that makes sense to Visual Basic. Note: it does need to be strict in the language sense - Visual Basic programmers often don't care about the difference between an empty string and null, but the language must. And how to handle Option Binary/Text, Option Explicit and Option Strict. |
@MohammadHamdyGhanem Equals can be overridden on a type to return a different value than the equals operator. It's certainly a bad idea, but the language still needs to handle it correctly. In this case, it would be weird for the = operator on a tuple to follow Equals, and not =. That's why C# chose to recursively compare each item with the == operator. It could be that VB just needs identical rules with extra paragraphs for the Option cases. I believe that the less subtle differences with C# the better. |
@reduckted @Berrysoft @Nukepayload2 @KathleenDollard @srivatsn
And used it like this:
As I said: I see no problem at all. We need to do nothing more. We just compare each pair with = operator or <> operator, and VB.NET will apply all its roles! |
Your function only works as long as the file it is compiled in has the same Options Compare value as the file using it. This has bitten me more than once, there probably should be an analyzer to detect public functions that compare strings even today.
|
@paul1956 |
@MohammadHamdyGhanem as a library your example has the issue I posted, if your intent is to have the compiler generate the code inline then I agree. Also there is a feature request to let Options be applied to blocks, this would address the issue if you want to use your code in a library and today you can disable the warning manually around the call to AreEqual and shown in #117 . |
@paul1956 |
@MohammadHamdyGhanem I never trusted, agreed with or remember the defaults, and I reuse a lot of source between projects so I specify Options in every file if it matters. |
We'll take this as a request to support elementwise equality operators for tuples in VB. |
@gafter |
Wait, we did add minor versions. In language version 15.3 we added tuple element names inferred from the tuple expressions, and in 15.5 we added support for a digit separator |
I thought this was in the docs, but found this quicker: https://stackoverflow.com/questions/32122660/how-to-change-the-vb-net-language-version-in-visual-studio-2015 There are two reasons you might think there are no minor updates:
But when you set via the project file, you get the new features. |
@KathleenDollard |
@KathleenDollard Those instructions really don't help much with VS17 where the line you need to change is not 4 and the value you need to set it to is not obvious. At a minimum there should be detailed instructions so that us dumb VB users can follow them. It is sort of backwards, C# has expert developers but they get super support including a QuickFix, but beginner VB users are told to hack XML without instructions of what we are even supposed to hack and when you click on the error in VS you get C# instructions. Sorry for venting. Also instructions need to be provided for running tests using new features. |
@MohammadHamdyGhanem I understand your frustration. As to the What's New: @jcouv created a doc to make it easy for people to work on this. Language-Version-History.md. @gafter pointed out wikipedia is a source for VB history. As for setting the language version: I don't know why I didn't see this before, but directions for setting the Visual Basic language version have been in the docs for some time. I don't remember what I searched for, but if anyone has a search they think should find this page that doesn't, I'll pass it on to docs and see if they can improve the SEO. |
@KathleenDollard "setting VB language version" is the search I tried but the link in the error is really the issue, where there are instruction saying use "15.6", and several useless issues and the one you point to is not listed.
|
Paul, Would you mind opening an issue in dotnet/roslyn asking that the error message be updated to include the link. That seems doable shortish term. Kathleen |
I agree with @gafter and @KathleenDollard on elementwise Select Case obj.GetType()
Case GetType(Integer)
End Select Likewise, if you just use element-wise recursive Select Case GetVelocity()
Case (0, 0) ' Standing still
End Select (Of course, you might want to optimize the codegen for that code pattern). |
@ghost: I'd suggest changing the example to:
Because the fact that it can't compare two different types is irrelevant, if it can't compare the same types. |
I tried this code:
But VB.NET says:
The unusual thing is that C# accepts this:
Why can't VB.NET compare the two tuples, while C# can?
Note that VB.NET has no problem in assigning one of the tuples to the other one:
t1 = t2
The text was updated successfully, but these errors were encountered: