Allow the definition of extension methods in a namespace
I propose we allow the definition of extension methods in namespaces.
The existing way of approaching this problem in F# is to put the extension methods in a module, perhaps with the [<AutoOpen>] attribute to reduce friction for the user.
This approach is used because extension methods compile as static methods in a static class, and the F# 2.0 design took the "WYSIWYG" approach where an implicitly created module in a namespace felt odd.
However, in F# 4.x this seems somehow seems less odd, especially since [<AutoOpen>] can already been used to get much the same effect.
Pros and Cons
The advantage of making this adjustment to F# are orthogonality
The disadvantage of making this adjustment to F# is that the extensions will end up in a module with an implicit name, and we need a rule to decide that name in a stable way.
Extra information
Estimated cost (XS, S, M, L, XL, XXL): M
Affidavit (please submit!)
Please tick this by placing a cross in the box:
- [x] This is not a question (e.g. like one you might ask on stackoverflow) and I have searched stackoverflow for discussions of this issue
- [x] I have searched both open and closed suggestions on this site and believe this is not a duplicate
Please tick all that apply:
- [x] This is not a breaking change to the F# language design
- [x] I or my company would be willing to help implement and/or test this
What would be the impact (if any) with regards to let bound functions? Occasionally I find myself creating them in AutoOpen modules e.g. Helper functions, or functions that act on domain types in the parent namespace.
Also what would the interop story with other .NET languages look like?
Also what would the interop story with other .NET languages look like?
For extension methods, I believe they would only have to open the relevant namespace.
What would be the impact (if any) with regards to let bound functions?
@isaacabraham Yes, that's much the same issue, and could be solved the same way. However for other .NET languages they would need to know the magically created static class name
It's great. Kotlin, for example, allows to define extension functions locally, inside other functions, which is very handy and does not pollute global scope:
private fun getSourceString(source: Any): String {
fun String.upper() = this.toUpperCase()
// or just `fun String.upper() = toUpperCase()` - implicit `this`
return when (source) {
is String -> source.upper()
is Timer -> "timer '${source.name}'".upper()
is IActorRef -> source.toString().upper()
else -> "unknown".upper()
}
}
The syntax is super lightweight BTW (Type.extensionName plus implicit this)
What about a general proposal to allow types defined locally in a function?
Then the combination of both (local types & extension methods without a module) would allow something similar to Kotlin:
let f() =
// I can either declare a normal type ...
type R = { A : int }
// or an extension method ...
type string with
member x.upper() = x.ToUpperInvariant()
// both are only in scope inside f!
...
For extension methods, I believe they would only have to open the relevant namespace.
What would be the impact (if any) with regards to let bound functions?
Yes, that's much the same issue, and could be solved the same way. However for other .NET languages they would need to know the magically created static class name
+1 for extension members without a module, because consumers only need to open the namespace and don't need to care about the generated class.
For the same reason -1 for ordinary let bound functions, because the wouldn't be consumable from C# without knowing the generated name.
What about a general proposal to allow types defined locally in a function?
That's covered by https://github.com/fsharp/fslang-suggestions/issues/150
What about a general proposal to allow types defined locally in a function?
I really just want to be able to open namespaces/modules in every scope, that seems much more general purpose useful. Sorry to sidetrack, I think everything should be available in all scopes for symmetry. It makes the language more beautiful and easier to learn.
Overall this sounds conceptually simple and good. I'm all for this in let bindings because it could be a useful kind of information hiding just like every other construct in the language other than type definitions.
This suggestion would conflict with the ability for F# type extensions to interop with C# extensions since C# extensions must be in static classes.
Even when declared in an F# namespace, the IL codegen would still put them into an implicit module and C# compiler would see them within a static class.
Hmm, then C# would still need to using static that static class even as F# doesn't need to. This static class has to also maintain binary compatibility without changing the name.