Yes, there have been lots of suggestions that boil down to a shorthand way to express things, so that instead of the verbose

... (fun x -> x.Blah maybeMore) ...

what if there were some compact form, like

... (.Blah maybeMore) ...
... _.Blah maybeMore ...
etc.

(where the type coming in has already been inferred).

Additionally people want compact ways to transform instance methods into functions-that-take-the-(non-type-inferred)-receiver-as-an-argument, e.g. instead of

(fun (s:Dictionary<_,_>) -> s.Keys)
(fun (s:Dictionary<_,_>) k -> s.ContainsKey(k))

have e.g.

Dictionary<_,_>#Keys
Dictionary<_,_>#ContainsKey

The most common places you want these is when working with OO types either in pipeline or in conjunct with higher-order functions.

We've investigated and debated a number of these sugars, but never found a design we love.

As shown above, in a pipeline today, you can pretty much always wrap

(fun x -> xCODE)

around your member CODE, e.g. the wished-for .ToUpper() becomes

(fun x -> x.ToUpper())

By on 3/5/2010 9:33 AM ()

> never found a design we love

What's not to love about "IJW" here? (Hell, if you can get C++ and .Net to "IJW", you can do almost anything...) If for some reason there's an ambuguity, it can be treated as an error.

... |> .ToLower |> ...

Seems quite natural and unambiguous.

However, this is different than

... |> y.StartsWith |> ...

which would pipe into the arg, not the object sender, which is already specified.
Given that this already works in the current system:

> "aa" |> "aaa".StartsWith;;
val it : bool = true
>

It seems reasonable to me to have the first (arguably more primitive) case work as well.

By on 3/5/2010 10:49 AM ()

anotheraccount, the proposition looks nice, but it has a few problems. As it would be a bad idea to allow this syntax only in a pipeline, the following would therefore be valid:

let (f: string -> int) = .Length

But... what about "f .g". Would it be (f.g) or f (.g) ? Your proposition brings some ambiguity.

The syntax "_.Method" is cleaner and solves this problem, but the underscore is already used with a different meaning, which could be confusing for many people. Also, this looks like the syntax used in Nemerle (cf. [link:nemerle.org] which I love. But, for consistency, it would be better (like in Nemerle) to use the underscore for partial application. But then it would change a few things, and it's not that simple...

Laurent.

By on 3/5/2010 5:01 PM ()

Not all ambiguities need be resolved syntactically only - but that certainly makes things easier for the dev. env., as these don't typically have deep hooks into the compiler. (This also bugs me with "please supply extra parens" error message - altough syntactically ambiguous, it's rare that muiltiple parsings are semantically type-valid as well.)

But in this case it seems like documenting the relative precedence of application vs. cloure-creation of members would solve the problem, just as we know that 2+3*4 is 14 and not 20. In the case, the (f.g) meaning seems the obvious choice.

By on 3/6/2010 11:05 AM ()

The best idea would probably be to use a different character like #, @, ' (easily distinguishable when used to introduce a generic type), Ϫ etc. :-)

By on 3/6/2010 4:51 PM ()

I'd prefer |> .member, since it's sort of intuitive to read -- though the F# compiler is already sort of on the slow side and we're already flooding the devs with feature requests, so if it needs to be something simpler, then I would take that too.

Whatever the case, it'd be best for it to be conducive to good IntelliSense.

By on 3/10/2010 4:15 PM ()

>though the F# compiler is already sort of on the slow side

I'm curious about when this comes into play for most people. I'd gladly have the compiler be ten times slower than it is if it in general meant getting more powerful constructs.

(Once you've swapped 8" floppies about 10 times to compile a simple C program saving intermediate files between cpp, cc1, cc2 and the linker, it's all good :))

By on 3/20/2010 10:42 PM ()

I agree, I'd be willing to trade off a LOT of compiler performance for language features. This is especially true for a language like F# that supports interactive testing, and a system like .NET that supports assemblies.

I don't dispute that waiting for a compile can be irksome, but in the final analysis, it's a minor part of the coding lifecycle. And the mind is a neural net, not an overclocked CPU; sometimes a little quiescence lets it converge onto better solutions, lol.

-Neil

By on 3/21/2010 8:09 AM ()

It's a bit better on my new quad core machine than on my Centrino Duo laptop, but what tends to happen is that in a large source file, I'd be sitting there waiting for the IDE to finish background compilation every time I tweak some code so that I can tell whether or not I managed to confuse type inference.

But you're right, even then, this would be a nice feature to have.

By on 3/21/2010 11:56 AM ()

What about a code generation hack? Point a script to a dll and have the script generate a module that has all of the methods as functions that take the object as the first parameter.

Something like this, when pointed at System.Core.dll:

1
2
3
4
5
6
7
8
// ... 


module Microsoft_Win32_SafeHandles_SafeNCryptHandleFn =
  let get_IsInvalidFn (obj: Microsoft.Win32.SafeHandles.SafeNCryptHandle)  = obj.get_IsInvalid()
  let DangerousGetHandleFn (obj: Microsoft.Win32.SafeHandles.SafeNCryptHandle)  = obj.DangerousGetHandle()
  let get_IsClosedFn (obj: Microsoft.Win32.SafeHandles.SafeNCryptHandle)  = obj.get_IsClosed()
// ...

I put some partial code up at [link:gist.github.com] to do this - just pass it -d SomeDllName and it'll produce the code above. It's not functional yet (I'm off to a dinner party right now) but might be interesting.

By on 3/5/2010 5:16 PM ()

> Another way (maybe nicer) to achieve this would be to have the dot (.) as a meta-operator that returns an object function.

Yeah, baby - now we're cookin' with bacon!

Whether it's an actual operator, or just a compiler niceity, I think the effect of being able to treat unbound method callls as curried fn's is great. (I say "treat as" because I don't think there's a need to create an actual closure if you're just going to call the method via |>, only if your going to pass it as a higher-order fn more generallly.) This would pretty much make F# a fully armed and operational battle station of blended OO and functional goodness.

+1

By on 3/5/2010 9:26 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper