Reputation: 17196
I think this code I wrote to copy object property trees is pretty functional - does the F# version bring another level of succinctness?
public static class CopyUtility
{
public static void Copy(object source, object target)
{
(
from s in Properties(source)
from t in Properties(target)
where Matches(s, t)
select Action(t, target, s.GetValue(source, null))
)
.ToList().ForEach(c => c());
}
static IEnumerable<PropertyInfo> Properties(object source)
{
return source.GetType().GetProperties().AsEnumerable();
}
static bool Matches(PropertyInfo source, PropertyInfo target)
{
return source.Name == target.Name;
}
static Action Action(PropertyInfo source, object target, object value)
{
if (value.GetType().FullName.StartsWith("System."))
return () => source.SetValue(target, value, null);
else
return () => Copy(value, source.GetValue(target, null));
}
}
Upvotes: 3
Views: 693
Reputation: 6543
Here's the C# copy function translated to F#:
module CopyUtility
let rec copy source target =
let properties (x:obj) = x.GetType().GetProperties()
query {
for s in properties source do
join t in properties target on (s.Name = t.Name)
select s }
|> Seq.iter (fun s ->
let value = s.GetValue(source,null)
if value.GetType().FullName.StartsWith("System.")
then s.SetValue(target, value, null)
else copy value (s.GetValue(target,null))
)
Light syntax
F# uses a light syntax where white space is significant, which reduces the number of lines taken by curly braces. I counted 28 lines in the C# code versus 13 in the F# code.
Type inference
The F# copy
function requires only a single type annotation. Like C#, F# is a statically typed language, however F#'s type inference is not limited to local variables.
Nested functions
F# supports nested functions allowing the properties
function to be defined within the body of the Copy function. This could be also be done with C# by defining a lambda function of type Func<object,IEnumerable<PropertyInfo>>
but it is considerably less succinct.
Query syntax
F# 3's query expressions provide a succinct syntax similar to LINQ in C#.
Pipelining
The F# pipe forward operator (|>) enables function calls to be chained together as successive operations, often removing the need for temporary variable declarations.
Upvotes: 12