DavidArno / SuccincT

Discriminated unions, pattern matching and partial applications for C#
MIT License
267 stars 15 forks source link

SuccincT Roadmap #52

Closed DavidArno closed 4 years ago

DavidArno commented 6 years ago

@xlecoustillier, @gavinSteyn, @Odonno, @Opiumtm, @megafinz, I'm name checking you all here as you've previously contributed bug reports, suggestions or PRs and so may wish to join in this discussion. Apologies if you are no longer interested.

I've been very quiet regarding SuccincT now for a few months as I've been watching what has happened to C# with the v7.x releases and what's planned for v8, and trying to work out what to do with SuccincT as many of those new language features impact on the reasons for this library existing in the first place.

The key features that I feel have a big impact are:

  1. Readonly refs and readonly structs (C# 7.2)
  2. Nullable reference types (NRT) (C# 8)
  3. Recursive and parameter pattern additions to pattern matching (C# 8)

With the work around readonly structs and refs, I think it sensible to look again at the various option/union types and likely redo all of them as readonly structs.

Since the NRT will mean that reference types become non-nullable by default, the whole need for option/maybe types is called into question. If I can have string for when I definitely have a value, and string? for when I may not, what need is there for Option<string>? T? can be thought of as (an admittedly poor-man's) maybe type.

However, it's not exactly uncommon for null to be used as a value, so it's quite possible that people would want to be able to do something like Option<string?>. There is no T?? (whatever that would mean), so it probably makes sense to keep an option type in SuccincT.

The new features for pattern matching in C# 8 can be experimented with today using this prototype extension for VS2017. From the experiments I've done, I'm not sure there will be any need for SuccincT to have its own pattern matching features when C# 8 is released. So maybe they should be removed at that stage?

So my thoughts on a road map are:

Version 4 - Work can start on this straight away

  1. Remove either Option<T> or Maybe<T> and replace with a single readonly struct. I don't mind which name it has. I'm even open to calling it Optional<T> since that name has become popular too since Java added it.
  2. Replace the Union, ValueOrError and Success types with readonly structs.
  3. Switch the supported framework to netstandard 2 to allow us to add @Odonno's With features.
  4. Address issues/PRs #48 (@Odonno), #49 (@gavinSteyn), #50 (@xlecoustillier) and #51 (@xlecoustillier). Care needs taking with #49 though to ensure it doesn't cause problems with C# 8's pattern matching later (I don't think it will, but want to check).
  5. Make use of the new Enum generic constraint to tidy up the code around the enum parser.

Version 5 - For when C# 8 is released

  1. Ensure the code is compliant with NRTs,
  2. Mark the Match methods as deprecated,
  3. Create Rosylyn analyzer-based "code fixes" to automate rewriting SuccincT patterns into C# patterns. This is likely a lot of work, so this really is aspirational.

Version 6 - Maybe release around the time of v8.1

  1. Remove SuccincT's pattern matching support.

What are your thoughts on the above? Anyone have strong views on any of this? Or is it a case of "Whatever! You disappeared for so long, we've lost interest in SuccincT"? Am I being naive in thinking there's even a need for this library after v8 is released?

Please share your thoughts and don't spare my blushes. I've enjoyed working on SuccincT and I'm happy to put more work in if folk still want it. But I'm also happy to walk away and work on other things if it's coming to the end of its useful life.

Odonno commented 6 years ago

@DavidArno I am glad you gave us some news. Here is my reply regarding your library, the roadmap and obviously my interest in it.

First of all, SuccincT is underrated IMO. Bringing functional to C# is clearly interesting and more than useful. Even if C#8 will bring a lot of functional stuff, those who are using C#7 are still in the need. I am advocating it in my own way that will be described in another paragraph.

Then, my interests. I mostly use SuccincT for some features which are Option<T> and pattern matching. I sometimes have the need for ValueOrError<T> and Union<T> but clearly I would rather switch to the discriminated union in F# if I could instead of using struct/class/enum.

Regarding the With feature, it is vital to me because I am writing a library called ReduxSimple (https://github.com/Odonno/ReduxSimple) which is a .NET Standard library inspired by redux and it provides a FRP model to make .NET application with a Redux pattern. Functional mean having an immutable state (with Optional data) and each mutation of the state requires to update generally 1 or 2 properties. This is the perfect scenario for the With keyword and that's one of the reason I need it.

I am advocating it because I make SuccincT a strong dependency to ReduxSimple and in the future I plan to provide a toolbox to get started writing WPF/UWP/Xamarin app using ReduxSimple. I also tweet about it to other developers who struggles to find good alternatives to make C# functional.

That's all for me. And again, thanks for your involvement @DavidArno

EDIT: By the way, I did not watch the Build session about the future of C#. Will do asap.

DavidArno commented 6 years ago

@Odonno, Thanks for your kind words.

For those that haven't yet seen the Build presentation on the future of C#, you can find it at at https://channel9.msdn.com/Events/Build/2018/BRK2155. It's really worth watching. Especially at the end when Mads talks about records and the team's drive to make C# ever more functional. Left me with with a warm, happy feeling 😀

DeafLight commented 6 years ago

Hi @DavidArno, thanks for the update.

As for the non nullable reference types, in my mind they don't replace Option. While the purpose is almost the same, I feel really more comfortable when getting an Option rather than a Nullable, because of all the functional features, and because null is still a magnet for bugs and defensive code. Plus, it seems that they (NRT) will be a mess to apply in legacy code.

There are some libraries out there with a lot of identical usecases as SuccincT (I'm thinking of Vladimir Khorikov's Functional Extensions and Paul Louth's Language-ext for instance). I didn't test Functional Extensions, but SuccincT seems to be halfway between both (wider than Functional Extensions, and lighter than Language-ext). To be honest, we didn't take any decision yet on which one we'll end up using, but as far as I'm concerned, SuccincT remains interesting as it is a lot lighter than the 14MB of language-ext + deps.

Because of all that, and until C# gets to cover all those functional features, SuccincT definitely has its place among those other nice functional libraries.

Odonno commented 6 years ago

@xlecoustillier Like you said, Non-Nullable should work with Option<T> to separate those worlds like F# does.

Odonno commented 6 years ago

@DavidArno Do we have a release date for 4.0? I would like to get a release by the end of this month if possible.

If you don't want a public release, you can mark your nuget package with a suffix (like -preview or -alpha).

kgreen24 commented 6 years ago

@Odonno seconded, I recently put in a new method for Unions called HasValueOf, but I realized it's doing strict type checking which I actually don't want, so I am going to put out a PR to convert that to an "is" check.

DavidArno commented 6 years ago

@Odonno, I avoid committing to release dates in my day job, let alone "hobby" stuff 😆

I've been looking into how the pattern matching features will likely work in C# 8. One of the consequences of the way they will work is that what I'd planned is unsafe as it relies on behaviour of the prototype compiler, which is not guaranteed to remain unchanged.

As a consequence, I need to put the idea of changing the option and union types into read-only structs on hold. As a result, the road map has basically changed before I even start.

At the moment, I'm looking stuff related to #38, with the idea of having TryXXX methods return Option<T> and MaybeXXX methods return Maybe<T>. Once that's done I can then come up with a new roadmap and think about timescales.

I'm on holiday for much of the next week or so, so please don't expect any real progress on this until early June.

DavidArno commented 6 years ago

Right after much trashing of ideas, here's what I've come up with for handling pattern matching. If I add a two parameter Deconstruct method to each of the types - eg for Union<T1, T2>, we have:

public void Deconstruct(out Variant validCase, out object value) 
    => (validCase, value) = (Case, Case == Variant.Case1 ? (object)_value1 : _value2);

- then it becomes fairly easy to use them in pattern matching:

var x = new Union<int, string>(1);
var y = x switch
{
    (Variant.Case1, int i) => i.ToString(),
    (Variant.Case2, string s) => s,
    _ => default
};

So I'm happy I have a solution that doesn't require type hierarchies, thus allowing these types to be converted to structs.

The only issue there is that the union types all implement IUnion<T1, T2, T3, T4> to allow them all to use the same pattern matching code. If I'm going for structs, then this code needs a rethink. So that's the next thing for me to look into.

kgreen24 commented 6 years ago

@DavidArno , do you happen to have a sense of when the next release may be? I'm considering putting out a PR to make the HasValueOf I added to Unions behave polymorphically.

DavidArno commented 6 years ago

@kgreen24,

I've now stripped out the Maybe type and turned Option into a a struct. The unions now no longer implement IUnion and so are now ready to be turned into structs too. So that's the bulk of that restructuring task out the way. So I'm now aiming for mid July (say around the 14th) for the v4 release. No promises though 😉

DavidArno commented 5 years ago

OK, as it's been nine months since I last posted to this thread, I thought it long past time for an update:

Status update: "Succinct isn't dead, it's just deeply confused".

For many months now, the code for v4 has been pretty much done. Maybe<T> is gone, Option<T>, Either, Union<...> etc have all been converted to structs, missing pattern matching functionality added and various submissions by you folk added. The docs are even pretty much finished (I think there's stuff about the new generic ValueOrError to write up and a load of proof reading to do, but that's about it.

So what's the problem? Well C# 8 is the problem (sort of). I started playing around with Null Reference Types (NRTs) and the improved pattern matching features before releasing v4 of SuccincT. This partly meant I got distracted and never quite released it. But more significantly, I started seriously questioning changing all those types to structs as generic structs really do not play nicely with the NRT feature.

To explain this, consider the following:

public struct Foo<T>
{
    public Foo(T param) => Property = param;
    public T Property { get; }
    private bool EqualsOtherFoo(Foo<T> other) => Property.Equals(other.Property);
}

This will give the warning:

Warning CS8602  Possible dereference of a null reference.

for Property.Equals. The reason being that dreaded feature of structs: zero filled defaults. If I do:

var foo = default(Foo<string>);

foo then contains a null backing field for Property. And it's not possible to just change that Foo<T> to Foo<T?> as now it needs T constraining to either a class or struct as nullable ref types and nullable value types are very different things as far as the CLR is concerned.

The more I experiment with NRTs, the more I feel v4 has lead me down a rabbit hole and I'm endlessly digging to try and resolve all the NRT warnings I get when I enable the feature. I'm therefore now sorely tempted to call time on v4 and abandon it. The non-breaking changes made (ie, pretty much everything except the changes to make Option<T> etc structs would then be added to a v3.3 release and then I'd create a new v4, which would be focused on the whacky world of NRTs and making SuccincT work nicely with them.

Does anyone have a view on this? Or have you all long ago given up on there being another release and you've all moved on to other solutions or created your own forks?

DavidArno commented 4 years ago

A year later … and v4 is finally released. So I'm going to close this issue and open a new one with ideas on where next, or whether this is likely to be the last release (save for bug fixes).