Awesome examples, thank you. I apologize if you already know all of this stuff. You seem much more knowledgeable about this than me.
As for type inference, C# will sometimes infer the RHS from the LHS, lambdas are one example. Also sometimes it can figure out the types from a lambda. Here is an example where the type information for inference comes from the literal int zero:
public void Main()
{
var i = 0;
var list = MakeThree(() => i++);
//[0, 1, 2]
}
private IList MakeThree(Func generator)
{
return new List{ generator(), generator(), generator() };
}
C# will infer method type parameters from arguments. In your example, there wasn't a type on the parameter to use as a source of inference. You could write it instead as (contrived example):
Predicate p = s => s.Contains("foo");
var foo = Foo(p);
The type parameter on Foo is inferred, as well as the variable type on the LHS. The only time I write a type on the LHS is when I am assigning a lambda to a variable. And that is not super often. More realistically though, you would be passing a collection or something else that already has a type. For example in LINQ's IEnumerable extension methods, the IEnumerable is the source of the type information as the first parameter to the extension method, so everything is inferred from there. It's extremely rare for me to type a method type parameter. I cannot remember the last time I did. I do write the types for constructors often, though. new List(), new Dictionary() etc. I guess the tradeoff is that in java you can infer a lambda's type by writing it on the LHS, while in C# you are going to have to get that type from somewhere else. Either write it on the RHS, or it will be written on some other variable or method.
Also I use Func and Action every day, but I basically never use other delegate types.
Your example of structure typing of lambdas looks weird to me. It's the same feeling I get when I see a downcast. I mean no criticism; I suspect this is a Blub reaction in me. I am not used to looking at the left-hand side to figure out the type for the right-hand side. Lambdas will implicitly convert to a Func or Action. A reference to a method with a matching signature will also convert. As a silly example: Select takes a Func, and will implicitly convert a method that accepts the same T as its only parameter.
public ShortTons ConvertTons(LongTons t) { ... }
public void Main()
{
var readings = GetReadings();
var exportWeights = readings.Select(x => x.Weight).Select(ConvertTons);
}
In this example, there are elided, inferred type parameters everywhere. The source of the type is in the missing GetReadings method, and the Weight property on the reading type. That's pretty typical.
That builder pattern is pretty cool. In C# you have object initialization syntax, which is similar in being more readable as to which members are getting set. However, that's pretty much incompatible with immutability afaik. It only lets you set public properties with public setters. Normally you would make something immutable by making your setters private, or leaving them off entirely. Public fields (even readonly ones) are strongly discouraged in C#. Either way, that prohibits object initialization.
Thanks for responding, I learned a lot about Java.