In C# I would implement Equals for a class with structural equality like this:
public override bool Equals(object obj)
{
if (this == obj)
{
return true;
}
var other = obj as MyType;
if (other != null)
{
return someField == other.someField &&
someOtherField == other.someOtherField;
}
return false;
}
In F# we have records for this, but if we want to use inheritance a type must be implemented.
What is the equivalent Equals implementation in F#?
As mentioned in the comments, you just need to override Equals. The compiler will also tell you that it is a good idea to override GetHashCode.
One neat trick is that you can just take all the relevant fields of your class, create tuples with them and then compare the tuples (or take hash code of the tuple). This makes the implementation much easier than if you were doing this by hand:
type Person(name:string, age:int) =
member x.Name = name
member x.Age = age
override x.GetHashCode() =
hash (name, age)
override x.Equals(b) =
match b with
| :? Person as p -> (name, age) = (p.Name, p.Age)
| _ -> false
Person("Joe", 42) = Person("Joe", 42)
Related
Let's say I have:
class Test<T> {
void method() {
if (T is int) {
// T is int
}
if (T == int) {
// T is int
}
}
}
I know I can override == operator but what's the main difference between == and is in Dart if I don't override any operator.
Edit:
Say I have
extension MyIterable<T extends num> on Iterable<T> {
T sum() {
T total = T is int ? 0 : 0.0; // setting `T == int` works
for (T item in this) {
total += item;
}
return total;
}
}
And when I use my extension method with something like:
var addition = MyIterable([1, 2, 3]).sum();
I get this error:
type 'double' is not a subtype of type 'int'
identical(x, y) checks if x is the same object as y.
x == y checks whether x should be considered equal to y. The default implementation for operator == is the same as identical(), but operator == can be overridden to do deep equality checks (or in theory could be pathological and be implemented to do anything).
x is T checks whether x has type T. x is an object instance.
class MyClass {
MyClass(this.x);
int x;
#override
bool operator==(dynamic other) {
return runtimeType == other.runtimeType && x == other.x;
}
#override
int get hashCode => x.hashCode;
}
void main() {
var c1 = MyClass(42);
var c2 = MyClass(42);
var sameC = c1;
print(identical(c1, c2)); // Prints: false
print(identical(c1, sameC)); // Prints: true
print(c1 == c2); // Prints: true
print(c1 == sameC); // Prints: true
print(c1 is MyClass); // Prints: true
print(c1 is c1); // Illegal. The right-hand-side must be a type.
print(MyClass is MyClass); // Prints: false
}
Note the last case: MyClass is MyClass is false because the left-hand-side is a type, not an instance of MyClass. (MyClass is Type would be true, however.)
In your code, T is int is incorrect because both sides are types. You do want T == int in that case. Note that T == int would check for an exact type and would not be true if one is a derived type of the other (e.g. int == num would be false).
Basically, == is equality operator and "is" is the instanceof operator of Dart (If you come from Java background, if not, it basically tells you if something is of type something).
Use == for equality, when you want to check if two objects are equal. You can implement the == operator (method) in your class to define on what basis do you want to judge if two objects are equal.
Take this example:
class Car {
String model;
String brand;
Car(this.model, this.brand);
bool operator == (otherObj) {
return (otherObj is Car && other.brand == brand); //or however you want to check
//On the above line, we use "is" to check if otherObj is of type Car
}
}
Now you can check if two cars are "equal" based on the condition that you have defined.
void main() {
final Car micra = Car("Micra", "Nissan");
print(micra == Car("Micra", "Nissan")); // true
print(micra is Car("Micra", "Nissan")); // true
}
Hence, == is something you use to decide if two objects are equal, you can override and set it as per your expectations on how two objects should be considered equal.
On the other hand, "is" basically tells you if an instance is of type object (micra is of type Car here).
public partial class Device : MarshalByRefObject
{
internal bool FindTagName(string name, OneTag tag)
{
foreach (FuncSect fs in listFuncSect)
{
foreach (OneTag ot in fs.listTags)
{
if (ot != tag && ot.Name == name) return true;
}
}
return false;
}
still have no idea how to convert this "partial" and "internal" to F#
thank you
As leppie says, there's no direct support for partial, although you could achieve a similar effect with intrinsic type extensions. F# does support internal methods, so your example would look like:
// primary definition somewhere
type Device() =
inherit MarshalByRefObject()
...
// type extension (roughly equivalent to partial class)
type Device with
member internal this.FindTagName(name:string, tag:OneTag) =
listFuncSect
|> Seq.exists
(fun fs ->
fs.listTags
|> Seq.exists (fun ot -> ot <> tag && ot.name = name))
partial is a C# compiler feature, it ain't gonna work on F#, you will have to combined all the partial classes, or inherit from an existing one.
I would like to override >= operator in Groovy, have found this page, but I am still not sure how to do it. I have a class Banknote with properties serial and amount and I wish to implement comparison bases on the amount property.
You don't override the >= operator, you implement compareTo:
class Foo implements Comparable {
int val
int compareTo(Object o) { return val <=> ((Foo) o).val }
}
f1 = new Foo(val: 5)
f2 = new Foo(val: 10)
println f1 <= f2
=> true
I just found such question on C# and converted some code to F# but sadly it still being returning it's name. The question is: where is my mistake? or is there alternative ways to have some enum-like structure with optional string returnin when I want to get A.B.ToString()
Here is my try:
[<TypeConverter(typedefof<EnumToStringUsingDescription>)>]
type FontVariant =
| [<Description("small-caps")>] smallCaps = 0
and
type EnumToStringUsingDescription() =
inherit TypeConverter()
override X.CanConvertFrom(context : ITypeDescriptorContext, sourceType : Type) =
sourceType.Equals(typedefof<Enum>);
override X.CanConvertTo(context : ITypeDescriptorContext, destinationType : Type) =
(destinationType.Equals(typedefof<String>));
override X.ConvertFrom(context : ITypeDescriptorContext, culture : System.Globalization.CultureInfo, value : obj) =
base.ConvertFrom(context, culture, value);
override X.ConvertTo(context : ITypeDescriptorContext, culture : System.Globalization.CultureInfo, value : obj, destinationType : Type) =
if (not <| destinationType.Equals(typedefof<String>)) then
raise <| new ArgumentException("Can only convert to string.", "destinationType");
if (not <| value.GetType().BaseType.Equals(typedefof<Enum>)) then
raise <| new ArgumentException("Can only convert an instance of enum.", "value");
let name = value.ToString();
let attrs =
value.GetType().GetField(name).GetCustomAttributes(typedefof<DescriptionAttribute>, false);
if (attrs.Length > 0) then attrs.[0]
else value
There are a couple of problems here. First, adding a TypeConverter will not influence .ToString().
Second, your conversion returns the attribute, not the description in the attribute. Here's a working function.
let getEnumDescription (value: Enum) =
let typ = value.GetType()
let name = value.ToString();
let attrs = typ.GetField(name).GetCustomAttributes(typedefof<DescriptionAttribute>, false)
if (attrs.Length > 0) then (attrs.[0] :?> DescriptionAttribute).Description :> obj
else name :> obj
That said, certain libraries/frameworks will use a Type converter if available. Might look something like this. It may be that you have to implement ConvertFrom/CanConvertFrom as well, I'm not sure.
type EnumToStringUsingDescription() =
inherit TypeConverter()
override X.CanConvertTo(context : ITypeDescriptorContext, destinationType : Type) = (destinationType.Equals(typedefof<String>))
override X.ConvertTo(context : ITypeDescriptorContext, culture : System.Globalization.CultureInfo, value : obj, destinationType : Type) =
let typ = value.GetType()
if (not <| typ.IsEnum) then raise <| new ArgumentException("Can only convert from enum.", "value");
if (not <| typ.Equals typeof<string>) then raise <| new ArgumentException("Can only convert to string.", "destinationType");
getEnumDescription (value :?> Enum)
Since, as Robert mentioned, enums cannot have members, and therefore you can't override ToString, you could do something like this, as a sort of compromise:
type FontVariant =
| ``small-caps`` = 0
Then, printf works as desired:
printfn "%A" FontVariant.``small-caps``
> small-caps
Also, John's suggestion to use a discriminated union is a good one. They look just like enums, minus the numeric values:
type FontVariant =
| SmallCaps
override this.ToString() =
match this with
| SmallCaps -> "small-caps"
Use the %O format (%A will use Reflection and print the case name).
printfn "%O" FontVariant.SmallCaps
If you need the numeric value, as enums provide, you can define a property:
member this.Value =
match this with
| SmallCaps -> 0
printfn "%d" FontVariant.SmallCaps.Value
Consider my first attempt, a simple type in F# like the following:
type Test() =
inherit BaseImplementingNotifyPropertyChangedViaOnPropertyChanged()
let mutable prop: string = null
member this.Prop
with public get() = prop
and public set value =
match value with
| _ when value = prop -> ()
| _ ->
let prop = value
this.OnPropertyChanged("Prop")
Now I test this via C# (this object is being exposed to a C# project, so apparent C# semantics are desirable):
[TestMethod]
public void TaskMaster_Test()
{
var target = new FTest();
string propName = null;
target.PropertyChanged += (s, a) => propName = a.PropertyName;
target.Prop = "newString";
Assert.AreEqual("Prop", propName);
Assert.AreEqual("newString", target.Prop);
return;
}
propName is properly assigned, my F# Setter is running, but the second assert is failing because the underlying value of prop isn't changed. This sort of makes sense to me, because if I remove mutable from the prop field, no error is generated (and one should be because I'm trying to mutate the value). I think I must be missing a fundamental concept.
What's the correct way to rebind/mutate prop in the Test class so that I can pass my unit test?
As a side-note, I would probably use if .. then instead of the match construct as it makes the code more succinct (patterh matching is especially valuable when you need to test the value agains multiple complex patterns). Also, public is the default access for member, so you can make the code a bit more succinct:
type Test() =
inherit BaseImplementingNotifyPropertyChangedViaOnPropertyChanged()
let mutable prop : string = null
member this.Prop
with get() = prop
and set(value) =
if value <> prop then
prop <- value
this.OnPropertyChanged("Prop")
Try this:
type Test() =
inherit BaseImplementingNotifyPropertyChangedViaOnPropertyChanged()
let mutable prop: string = null
member this.Prop
with public get() = prop
and public set value =
match value with
| _ when value = prop -> ()
| _ ->
prop <- value
this.OnPropertyChanged("Prop")
You need to make the binding mutable and then alter its value in your setter. In your initial code, you were just creating a new binding (also called prop) within your setter, so no change was visible.
In your pattern match you are actually binding a new value with
let prop = value
When you bind a value like this with the same name, it will shadow the other value for the scope of the newly declared one. I believe what you actually want to do is this:
prop <- value