

Show HN: C# 6.0 Functional Language Extensions - louthy
https://github.com/louthy/language-ext

======
MichaelGG
Coercing Some (null) to None seems like a bug. Null is a valid value in the
type and should be allowed (F# allows it too).

Otherwise, a function might accidentally return None and cause a bug. For
instance, a function that looks up s user and returns the name. The name might
have null as a valid option. Some(null) indicates user found with no name.
None indicates user not found.

~~~
louthy
I hear what you're saying, but I felt that the reason for using Option in C#
would be explicitly to deny nulls. If you are OK with accepting null, don't
use Option and return null.

I think that's slightly different with F# where you mostly deal with value
types that definitely have values. It's rare that you need to pull null out of
the bag (unless interop'ing with .NET libs).

I understand why you might call it a bug, but I think I make the reasoning
clear in the documentation. So I hope it's unlikely to cause confusion.

~~~
lomnakkus
The proper way to do this is to have something like in Scala where you say

    
    
        Option(foo)
    

if you want "foo" coerced to either Some(...) or None based on its nullity. It
doesn't prevent you from using

    
    
        Some(null)
    

if that's what you _really_ mean. (Though I think it might be a reasonable
idea to actually throw an error in such a case. However, there should be a way
to construct a Some(null), perhaps with a name that suggests that it's not
recommended. Perhaps something with "unsafe" or "unguarded" in the name.)

~~~
louthy
> Perhaps something with "unsafe" or "unguarded" in the name.

That seems like a reasonable approach.

------
Strilanc
A comment on the option type: I think transforming Some(null) into None is
wrong.

\- There is an x for which Some(x) is not a Some. This violates useful
invariants. \- Some((int?)1) is a Some, but Some((object)(int?)1) is a None.
\- optionValue.Cast<object>().Cast<T>() is not the identity function. \- I
can't use your option type in existing code without doing careful null
analysis. \- As a rule of thumb, generic code you should treat null as just
another instance of T with no special treatment (beyond the acrobatics to make
the code not throw an exception). That way both users enforcing a non-null
constraint and users allowing nulls can use your type.

~~~
louthy
Just replied to MichaelGG on the same subject [1]. I understand what you're
getting at. I'm not particularly looking to create an algebraically perfect
type. The explicit reason for this is to kill null as a possible output from a
method, so that the consuming code only has Some or None to deal with. If you
want to return null, don't use Option<T>.

[1]
[https://news.ycombinator.com/item?id=8634015](https://news.ycombinator.com/item?id=8634015)

~~~
MichaelGG
It only has Some or None to deal with. Some<T> or None. Also, do you take it
all the way? By the current logic, Some(Some(null)) should also return None.

~~~
dragonwriter
If Some(null)is None, then shouldn't Some(Some(null)) be Some(None)?

But I'd agree that Some(null) should just be Some(null) and not magically
become None. Now, there should be a a generic function something like
NullableToOptional<T> that returns an Option<T> by mapping any non-null value
_v_ to Some( _v_ ) and null to None, but it shouldn't be the core behavior,
because you should be able to wrap a nullable value in an option.

~~~
louthy
This whole thread is food for thought definitely. I'll open an issue on the
github page to get some feedback. I think if Some(null) doesn't become None
then it should throw an exception instead rather than wrap null. I'm
explicitly trying to control the number of possible outcomes, passing null
back shouldn't be valid at all imo.

So perhaps the conversion logic should be:

    
    
        x = Some(x)
        null = None
        Some(x) = Some(x)
        None = None
        Some(null) = Exception
        Some(None) = Exception
        Some(Nullable null) = Exception
        Some(Nullable x) = Some(x)

~~~
wtetzner
I don't see any reason not to have Some(None) = Some(None).

~~~
louthy
I see your point, but what does it mean? It means returning an
Option<Option<T>>. I think I'd rather lift the value out automatically:

    
    
        Some(Some(x)) -> Some(x)
        Some(None)    -> Exception
    

Thoughts?

~~~
dragonwriter
> I see your point, but what does it mean? It means returning an
> Option<Option<T>>. I think I'd rather lift the value out automatically

Lifting the value out automatically loses much of the value of having option
types. A large part of the value of Option types is that they preserve
information that gets lost when using Nullable types for a similar purpose
_because_ you can nest them -- that is, the fact that Option<Option<T>> is a
thing you can use where Nullable<Nullable<T>> isn't is a big part of the point
of using an option type. Extracting the value is done explicitly.

~~~
louthy
Could you give a concrete example? I've personally never found myself wanting
to preserve nested options. What additional information does it preserve? I
could perhaps see the value if C# had decent pattern matching, I'm not
currently convinced it would bring much benefit to the average C# app.

~~~
dragonwriter
> I've personally never found myself wanting to preserve nested options.

Sure, but you never need to just because you can -- the most common use of
chaining calls that can produce Options in any language that supports them is
mapping functions accepting the wrapped type over the Options, which both
results in in one non-nested Option at the end of the chain and makes the fact
that the input is coming from an Option transparent to each of the calls in
the chain. If you don't need the information preservation of nested Options
(and its true that its less common that you do, and often Either is a better
choice than Option for preserving information), then you just don't bother to
explicitly wrap an Option in another Option.

Magically special casing it so that wrapping an Option in an Option flattens
it to a single, unnested Option doesn't seem to me like it serves much purpose
but ruling out a use case that Option types enable over nullable types,
because there's no reason you'd ever explicitly wrap an Option in an Option
unless you _wanted_ them nested -- and it makes the implementation more
complicated to impose that unnecessary limitation.

~~~
louthy
> because there's no reason you'd ever explicitly wrap an Option in an Option
> unless you wanted them nested

This line changed my mind. You're absolutely right.

Thanks for the feedback :)

------
louthy
Due to popular demand, there's now a NuGet package. My first attempt at a
NuGet package, so let me know if I've messed something up:

[https://www.nuget.org/packages/LanguageExt/0.0.1-beta](https://www.nuget.org/packages/LanguageExt/0.0.1-beta)

~~~
louthy
This is the general link, rather than directly to a version.

[https://www.nuget.org/packages/LanguageExt](https://www.nuget.org/packages/LanguageExt)

------
danbruc
I hope this does not come across to negative, definitely a nice project, but
is this really useful in practice? If you want F# or Haskell syntax, why not
just use F# or Haskell? Why bent C# until it looks like something that already
exists? If you work together with (pure) C# developers, you will just confuse
them. If you work together with Haskell or F# developers, you can just use
that languages.

If this is just a fun project, scratch what I said, I love building useless
stuff myself, but if it is intended to be used seriously I don't get the
point.

~~~
BigChiefSmokem
The importance lies in that C# is becoming one of the first truly, for lack of
a better word, "programmable" programming languages.

The One Language to rule them all? Maybe not, but definitely making incredible
progress.

~~~
SideburnsOfDoom
I'm not sure what you mean by that. I was under the impression that Common
Lisp macros were the first metaprogramming feature

[http://stackoverflow.com/questions/267862/what-makes-lisp-
ma...](http://stackoverflow.com/questions/267862/what-makes-lisp-macros-so-
special)

.. and not the last: [http://programmers.stackexchange.com/questions/97069/is-
ther...](http://programmers.stackexchange.com/questions/97069/is-there-a-
language-offering-lisp-like-macros-with-a-more-complex-syntax)

~~~
lispm
Well, Lisp macros as a meta-programming facility were introduced in 1963 by
Timothy Hart.

------
saosebastiao
Beautiful. I've been trying to pick up C# simply due to Xamarin, and this
definitely looks like it will make me feel more at home. Has anyone had
success with 6.0 on Xamarin? (Is it even out yet? I saw announcements, but
they looked like previews).

~~~
nbevans
Just use F# from Xamarin. It's the real deal. C# is just a stop-gap measure to
suck in the enterprise devs.

~~~
saosebastiao
Except that all the docs are in C#, which means if I want to consult them, I
have to either know C# or know how F# interops with C# (and therefore
understand C#). Trust me, I would love to, but I don't have the time to learn
two languages for one project.

~~~
MichaelGG
There is essentially no language specific documentation in well made APIs.
There is a common type system so there is very little that's different. Mainly
if you need a semicolon and how you prefer your parentheses.

There are some poorly made APIs, like ASP.NET MVC that exploit C#-specific
side effects to compensate for C#'s verbosity. These APIs ignore the common
type system and just pass object everywhere, breaking tooling and type safety.

But as long as Xamarin didn't come up with terrible designs, you're all set.
And, even if they do rely on something strange, F# is such a better language,
that the small setback of dealing with interop (which doesn't require learning
C#) is totally worth it.

~~~
icedog
I'm an F# developer, but still decided to not use F# to build an android app.
Dealing with the UI libraries like support.v4 was just too painful from a
functional perspective. If you don't need any object oriented dependencies,
then it's smooth sailing.

~~~
CmonDev
F# is not meant for implementing the complete app anyway. Just use it for
business logic where it makes sense.

~~~
MichaelGG
I've only heard that in context of A: missing tooling, B: Microsoft, in their
quest to make customers feel C# is still the real language and F#'s just some
science toy. I've used F# for a Web UI via WebSharper and it was lovely. It's
just a poor reflection on the state of UI kits if they don't work with F#.

~~~
CmonDev
"It's just a poor reflection on the state of UI kits if they don't work with
F#." \- well at least they don't start using lower-case names randomly.

------
steego
Funny I come across this today. Only yesterday did I start turning some of my
helper functions and extension methods into a little NuGet library. It's
amazing how much overlap there is between your library and mine, though I'm
probably going to steal some of your tricks. :)

While I do have an Option type with all the relevant LINQ operators defined,
I've resorted to using Nullable<T> for all string parsing functions that
return primitives as Nullable is a type that's actually supported databases.
For any nullable, I can use a nullableVar.DefaultTo(defaultValue) to convert
it to a non-nullable primitive type. Personally, I don't find Option types in
C# all that compelling because the pattern matching mechanism doesn't compel
you to handle all cases like F#.

All in all, it looks like an interesting library.

Thanks for posting!

~~~
louthy
Heh, that's really interesting! Do you have a link to your work?

> Personally, I don't find Option types in C# all that compelling because the
> pattern matching mechanism doesn't compel you to handle all cases like F#.

In my library you are compelled. You must provide both a Some and None
handler, even on the fluent variant. That was one aspect I absolutely wanted
to nail after doing a reasonable amount of F# work recently.

The only exception to that is you can ignore the Some branch, and just handle
failure. The Some branch then just uses an identity function behind the
scenes. So you're still compelled to deal with the failure case, which is
where I feel most of the C# null carnage comes from.

~~~
steego
> Heh, that's really interesting! Do you have a link to your work?

I do and I don't. I actually wrote a lot of these things in VB.NET 4-5 years
ago and I've recently returned to the .NET world, so I'm in the process of
converting it to C#.

There's a ton I haven't converted yet (Option types, lazy thunks that use
LINQ, Parser monads, LINQ Trees, etc.), and there's a ton I'm going to let die
out. :)

Here's a work-in-progress:
[https://github.com/steego/Steego.NET](https://github.com/steego/Steego.NET)

~~~
louthy
> There's a ton I haven't converted yet (Option types, lazy thunks that use
> LINQ, Parser monads, LINQ Trees, etc.),

 _ahem_ [https://github.com/louthy/csharp-
monad](https://github.com/louthy/csharp-monad) ;-)

> Here's a work-in-progress:

Cool, I'll take a look.

~~~
steego
> ahem [https://github.com/louthy/csharp-
> monad](https://github.com/louthy/csharp-monad) ;-)

Very nice! You may save me a bunch of work yet. We should get some of your
stuff into NuGet packages so you can spread the love. I saw on Twitter that
Miguel de Icaza approves of your library. :)

BTW, I just pushed up my little Tree library to my repo. Feel free to
incorporate and change it however if you like it.
[https://github.com/steego/Steego.NET/tree/master/Steego.Tree...](https://github.com/steego/Steego.NET/tree/master/Steego.Trees)

~~~
louthy
> I saw on Twitter that Miguel de Icaza approves of your library. :)

That's awesome! Thanks for sharing. I wouldn't even know how to get something
onto NuGet. I guess my weekend project might have to become a bit more serious
;) Time to do some research.

EDIT: research done...
[https://www.nuget.org/packages/LanguageExt/0.0.1-beta](https://www.nuget.org/packages/LanguageExt/0.0.1-beta)

------
tommyd
Impressive looking stuff - I'm currently learning Scala and getting deeper
into functional programming, and a lot of the concepts I come across (e.g.
Option types) make a lot of sense, so it's cool to see them being implemented
in other languages - hopefully with the recent MS announcement, I'll be able
to get back into C# development in the future as it's a pretty great language
all in all.

As an aside, I recognised your name in the example code on there - I used to
occasionally hang around on 4four :)

~~~
louthy
> I used to occasionally hang around on 4four

Nice. 4four's still going, but it's very quiet these days. Killed by the
Facebook behemoth. That's life, it was fun while it lasted :)

------
dstone16321
Feel free to pilfer some ideas from my own take on a similar lib for C#.
[https://github.com/danstone/lambit](https://github.com/danstone/lambit) \-
includes some basic pattern matching support for example.

This sort of library is kind of necessary I feel for things like poor tuple
support at least.

I'm not entirely sure about the casing conventions. I mostly code in
clojure/haskell/f# but 'when in rome'. Its likely the sort of thing that will
turn off a lot of stubborn developers.

~~~
louthy
Yeah I've implemented a similar pattern matching library before (not public
though). I always felt the syntax to be a bit 'bulky' because there were
always two lambdas, one for the predicate and one for the handler.

I like your take on list matching though, I think that's excellent and much
more usable. Not 100% sure how it could be adapted in a general way to the C#
Tuple though; because Tuple<A,B> is a different type to Tuple<A,B,C>. So you
could only ever match on one type (if you don't take the bulky predicate route
that is).

~~~
dstone16321
List matching tends to be fairly useful even its very limited form in my lib.
Its basically arity match + de-structure. It doesn't nest like full fat
pattern matching.

I don't see how tuple matching is as useful (over your 'With' fn or my
'Apply') unless it can nest, especially with matches on union types. e.g
(Maybe a, b) | (Nothing, b)

Basically I feel like such a thing is going to be very hard in C# to achieve
with any sort of usable api. I personally took the route of the api being more
important than whether any sort of decent abstraction is actually there behind
the scenes - I didn't mind writing 100's lines of boilerplate to get the
result and behaviour I wanted.

Its great to see more functional support for C# from the community and I look
forward to using your lib in the future!

------
martijn_himself
This is a really interesting experiment, although personally I'd find using:

var ab = tuple("a","b");

awful. It's very hard to read what is going on here- someone else reading your
code would be utterly confused. The method name starts with a lowercase
character, and I'm not sure I like the possibility to omit class names for
static classes (granted this is not your invention but a new C# feature
right?); to me it would seem it is missing the 'new' keyword.

I'd rather use Tuple.Create<T1,T2>(T1 first, T2 second) until they add proper
support for:

var ab = ("a","b");

~~~
louthy
That's fair enough. I knew implementing it this way would ruffle a few
feathers, and I totally understand why. I too would love to see ("a","b"), and
proper pattern matching... and ..

This was a weekend project that kind of grew over the past few days. Initially
I wasn't going to make everything lowercase, but I started thinking about the
fact that a lot of these functions are now essentially global and the
potential for clashes in real code. So I felt having a core set of useful
functions that look more like the lowercase keywords of C# rather than library
methods would work better. It definitely won't be everybody's cup of tea
though.

~~~
martijn_himself
I realise my comment is probably a bit too negative- I really like your ideas
(especially the Option type). Things like Tuple<T1,T2,T3> etc. make me wonder
if we would not all be better off though if we just started using F#...
although I still like C#.

~~~
louthy
> I realise my comment is probably a bit too negative

Not at all, you're entitled to your opinion. Whatever works for you :)

> we would not all be better off though if we just started using F#...
> although I still like C#

That would be nice. Unfortunately it's not always quite as easy as that. At
least in my corner of the world!

------
bbcbasic
I wonder what the impact is on performance of routinely wrapping your types in
Option<T>?

I am assuming it is minimal, because the struct would remain on the stack, and
the object on the heap. There is just an unwrapping and wrapping cost but no
more than Nullable? However this may be a naive view.

I like the syntax though. Where I work we use Code Contracts. This reduces
bugs due to nulls but sometimes 25% of the code is Contract.XXX(...) which is
annoying to read. And more typing too.

~~~
louthy
As you say the overhead should be similar to Nullable. And the struct _should_
be allocated on the stack, but the CLR doesn't guarantee that, so it can be on
the heap too.

There is however an 'if' in the constructor of Option<T>, so there's a little
extra potential branching overhead. For most scenarios I suspect this is all
moot, but if you're looking for the absolute maximum performance then you
would probably want to do some profiling before committing too heavily.

~~~
MichaelGG
The CLR has suboptimal codegen for structs, so there is likely an impact.

------
NKCSS
I didn't realy get the tuple part, if you want named properties, you can
always just do

    
    
      new { Name = "John", Age = 29 }; 
    

and you're there; no need for tuples and wrapping, etc.

~~~
louthy
You can't return anonymous types from functions.

------
bcbrown
Cool stuff. Isn't there still a problem with Option, where when a method takes
Option<T> as a parameter, invocations can pass null for that Option<T>? So
there's still the possibility of null exceptions.

~~~
infogulch
From the article:

> Option<T> works in a very similar way to Nullable<T> except it works with
> all types rather than just value types. _It 's a struct and therefore can't
> be null._

~~~
louthy
Exactly. Option<T> has a implicit conversion operator that converts a type of
T to Option<T>. So passing T to the function constructs a new Option<T>, and
the constructor checks for null. It's also likely (though not guaranteed) that
the Option<T> will be allocated on the stack, and should therefore not pose
too much of an overhead.

~~~
bcbrown
Awesome.

------
rukugu
I was thinking of writing something like this myself. This looks great!

------
TazeTSchnitzel
That definition of _cons()_ angers me. It's only useful for constructing
lists... not for constructing tuples and trees :(

------
CmonDev
This is a really cool exploration project, but hopefully I will not see this
in any production code. Way too un-idiomatic.

