Skip to content

[Proposal] Fluent parametrisation #635

@Orace

Description

@Orace

This is a proposal to unify lookalike methods.

An example of use with Zip is :

  source1.Zip(source2)   // ValueType creation overload
    .PadSource1With(foo) // zip parametrisation
    .PadSource2With(bar) // zip parametrisation
    .Where((a,b) => ...) // zip consumption
    . ...

Here are the methods signatures:

  ZipEnumerable<T1, T2, TResult> Zip(this IEnumerable<T1> source1, IEnumerable<T2> source2, Func<T1, T2, TResult> func) => new ZipEnumerable(source1, source2, func);
  ZipEnumerable<T1, T2, (T1, T2)> Zip(this IEnumerable<T1> source1, IEnumerable<T2> source2); // ValueType creation overload

// ZipEnumerable is a valid and honest IEnumerable
class ZipEnumerable<T1, T2, TResult> : IEnumerable<TResult>
{
  // immutable configuration
  readonly ZipConfiguration _configuration;

  ZipEnumerable(IEnumerable<T1> source1, IEnumerable<T2> source2, Func<T1, T2, TResult> func)
  {
  }

  // Return a enumerator that behaves according to the configuration
  public IEnumerator<TResult> GetEnumerator()
  {
  ...
  }

  // Configuration is fluent so updating it create an updated configuration and a new ZipEnumerable
  ZipEnumerable<T1, T2, TResult> PadSource1With(T1 padValue) => new ZipEnumerable<T1, T2, TResult>(_source1, _source2, _func, _configuration.WithPadSource1Value(padValue));

... // more configuration methods
}

The fluent parametrisation pattern have some rules:

  • configuration are immutable (for modification, create a new modified copy)
  • any configuration is attainable from any other configuration (any set can eventually be unset)
  • ?

Finally I expose the possibilities for Zip here as an example:

We have much more flexibility, for each source we can use one of those behavior :

  • End the result sequence on source sequence end. (It's the default behavior and, when used for all sources, it's equivalent to ZipShortest)
  • throw if the source is too short
  • perform padding with a static value
  • perform padding with the last value (we take care of empty source)
  • ...
source1.Zip(source2)
  .ThrowOnSource1Short(); // Throw only if source1 is too short
                          // stop if source2 too short (default behavior)

source1.Zip(source2)
  .ThrowOnSource1Short() // Throw only if source1 is too short
  .PadSource2WithLastOr(default); // Pad source2 with its last value (or the default value if it's empty)

source1.Zip(source2, source3, source4)
  .ThrowOnShort() // ask for equi zip
  .PadSource3With(foo); // This override the previous call and if source3 is too short it will be padded.

var zip1 = source1.Zip(source2); // zip1 is ZipShortest
var zip2 = zip1.PadSource1With(bar); // does not modify zip1

source1.Zip(source2); //ZipShortest (_do not do padding rule_)
source1.Zip(source2).ThrowOnShort(); // EquiZip
source1.Zip(source2).PadWithDefault(); // ZipLongest

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions