Sdk: Kotlin style receiver Function literals with receiver

Created on 4 Sep 2018  路  24Comments  路  Source: dart-lang/sdk

The request is to add Kotlin style receiver function literals and receiver function types language features to Dart. This will enable among other things writing Kotlin style DSLs for Flutter UI, configuration, etc.

Receivers are anonymous (not necessarily) methods that enables the access on visible methods and properties of a receiver of a lambda in its body without any additional qualifiers.

class Html {
    Body body;

    Body body(void Body.receiver()) {
        var body = Body();  // create the receiver object
        body::receiver();        // Invoke receiver with receiver object
        this.body = body;
        return body;
    }
}

class Body {
    List<Children> children;

    Div div(void Div.receiver()) { ... }
    P p(void P.receiver()) { ... }
}

Html html(void HTML.receiver()) {
    var html = Html();  // create the receiver object
    html::receiver();        // Invoke receiver with receiver object
    return html;
}

html(() {       // Anonymous function with receiver begins here
    body(() {
        div(() {
             // TODO
        });
    });   // calling a method on the receiver object without additional qualifier
});

We could go a bit further and make empty () optional in the context of an argument.

With higher order function syntax, this would look like this:

html {       // Anonymous function with receiver begins here
    body {
        div {
             // TODO
        };
    };   // calling a method on the receiver object without additional qualifier
};

It allows other cool things like let, apply, with, etc from Kotlin. It looks prettier and clearer than yaml and toml for configurations.

area-language core-n type-enhancement

Most helpful comment

Another example:

BEFORE:

return new Container(
  width: _kDotSpacing,
  child: new Center(
    child: new Material(
      color: color,
      type: MaterialType.circle,
      child: new Container(
        width: _kDotSize * zoom,
        height: _kDotSize * zoom,
        child: new InkWell(
          onTap: () => onPageSelected(index),
        ),
      ),
    ),
  ),
);

AFTER:

return Container{
    .width = _kDotSpacing;
    +Center{
        +Material{
            .color = color;
            .type = MaterialType.circle;
            +Container{
                .width = _kDotSize * zoom;
                .height = _kDotSize * zoom;
                +InkWell(
                    onTap: () => onPageSelected(index)
                )
            }
        }
    }
};

If dart ever comes up with an idea of how to make semicolons optional, this will remove all the remaining noise.
(With the old format, optional semicolons won't help at all b/c commas)

All 24 comments

So void Body.receiver() is the function type (or method type?) of a function taking no arguments, returning void and needing to be run with a Body instance as its this binding.

That would be a new kind of function type, but not particularly special type-wise. It could be considered equivalent to a function with an extra required (non-nullable?) "named" parameter named this with type Body. All type checking should otherwise work normally for that.
The invocation then passes the this argument along with any other arguments, and invocation proceeds normally, just with this bound to the special extra argument value.
So, from an object model or type system perspective, this is hardly a controversial feature.

So, it's most likely possible, the question is whether it's desirable for Dart as a language.

It's not great for readability that you cannot infer what this points to from the surrounding text. If you are of the "Explicit is better than implicit" school, then this is not an advantage. If you like writing DSLs (the epitome of implicitness), then it's likely a great feature.

So void Body.receiver() is the function type (or method type?) of a function taking no arguments, returning void and needing to be run with a Body instance as its this binding.

Yes, You are right. It is a function "receiver" type (or anonymous method type?).

That would be a new kind of function type, but not particularly special type-wise. It could be considered equivalent to a function with an extra required (non-nullable?) "named" parameter named this with type Body. All type checking should otherwise work normally for that.
The invocation then passes the this argument along with any other arguments, and invocation proceeds normally, just with this bound to the special extra argument value.
So, from an object model or type system perspective, this is hardly a controversial feature.

Yes! Just, would like to add that the this parameter is not exposed to the end user. It is implicit and hidden.

It's not great for readability that you cannot infer what this points to from the surrounding text. If you are of the "Explicit is better than implicit" school, then this is not an advantage. If you like writing DSLs (the epitome of implicitness), then it's likely a great feature.

You have listed some good concerns here. I like explicit programming (One of the reasons why I love Dart). But function receiver types and anonymous methods are completely explicit from context. I mean, you cannot have something like this:

// Not allowed!!!!! This is just a function or anonymous function. Not an anonymous method.
Function f = {
    body { ... }
};

It has to be either defined at a place where an anonymous method is expected or defined explicitly. Examples:

Example with explicit definition:

// Warning: Imaginary syntax. Declaring anonymous method named `myHtmlBuilder` on `Html`.
void Html.myHtmlBuilder() = {
    // It is very clear that this is anonymous method on `Html`
    body { ... }; // This is analyzable, easy to understand and totally explicit (As explicit as vanilla method)
};

Example with context:

// It is explicitly clear from `html` function's syntax that it is an anonymous method on `Html`.
// Also IntelliJ like parameter hint for implicit `this` parameter might be helpful.
html {
    body { ... }
};

Adding an example for Kotlin's with, let, apply, etc.

Standard library or support library level with:

Future<void> with<T>(T value, void T.receiver()) async {
    await value?::receiver();
}

Usage of with:

class Something {
  void something() { ... }
  void somethingElse() { ... }
  void newThing() { ... }
}

main() {
  ...
  with(Somethng()) {
    something();
    ...
    somethingElse();
    ...
    newThing();
    ...
  };
  ...
}

Declaring a method on Html, like:

void Html.myHtmlBuilder() {
    // It is very clear that this is a method on `Html`
    body { ... }; // This is analyzable, easy to understand and totally explicit (As explicit as vanilla method)
}

sounds remarkably like extension methods. The thing being asked for here is effectively to make function expressions that acts like extension methods, and which can be passed around like first-class objects before being bound to their receiver. That's more complicated than just scoped extension methods, because they bind the receiver late.

It's an interesting notion (I just read up on Kotlin's run/let/with/apply/also for a different reason). The underlying functionality would have something in common with extension methods, interface default methods and mixins - in all cases, a method is applied to another receiver than the one it was written for (if any). The one concept we do not have is a free first-class unbound method. That's a larger change to the function type system, but probably not a complex one.

If we want to add functions like the Kotlin apply or also, then we probably need self-types to express them. Perhaps through generic extension methods where the receiver is a type parameter.

The Dart versions of the Kotlin methods could be something like:

R T::let<T, R>(R Function (T) action) => action(this);  // Extension method on T, `this` has type T.
R T::run<T, R>(R Function (T) action) => this::action();
T T::apply<T, R>(R Function (T) action) { action(this); return this; }
T T::also<T, R>(R Function (T) action) { this::action(); return this; }
R with<T, R>(T object, R T::Function() action) => object::action();

(Except Dart wouldn't have apply and also, we'd just use cascades instead).

All in all, I like the idea. Not sure if we can make it a priority, though. It also matters whether we can do an efficient implementation of it, without inducing an overhead on code that doesn't use the feature.

@munificent (in case this might be useful for constructing UI).

sounds remarkably like extension methods

Yes. Kotlin's let, run, apply and also require extension methods. It would definitely be cool to have extension methods as proposed here, which seems to be a non-intrusive addition to Dart's simple type system. However, this enhancement request is strictly limited to "receiver functions" without the need for extension methods. Only with and similar patterns are within the scope of this proposal. That excludes let, run, apply and also but also opens door to have them in the future.

Receivers could be implement as an anonymous function with a hidden implicit required parameter called this of receiver's type. So there wont be any necessity to add extension methods or changing Dart's type system. This should work with existing type system.

For example:

This

// Warning: Imaginary syntax. Declaring anonymous method named `myHtmlBuilder` on `Html`.
void Html.myHtmlBuilder() = {
    // It is very clear that this is anonymous method on `Html`
    body { ... }; // This is analyzable, easy to understand and totally explicit (As explicit as vanilla method)
};

would translate into:

typedef Function = void HtmlBuilder(Html html);
HtmlBuilder myhtmlBuilder = (/* implicit Html this */) {
    // It is very clear that this is anonymous method on `Html`
    /*implicit this.*/body { ... }; // This is analyzable, easy to understand and totally explicit (As explicit as vanilla method)
};

and this

Html html(void HTML.receiver()) {
    var html = Html();  // create the receiver object
    html::receiver();        // Invoke receiver with receiver object
    return html;
}

translate into:

Html html(HtmlBuilder receiver) {
    var html = Html();  // create the receiver object
    receiver(html);        // Invoke receiver with receiver object
    return html;
}

So with a little syntactic sugar and no change to Dart's type system, we can implement receiver methods and hence DSL.

Either implemented like this proposal or using extension methods like Kotlin does, I feel "receiver functions" would be a great addition to Dart (especially Flutter and maybe even Angular).

Instead of introducing a whole new kind of function parameter, and answering the tricky questions around those (like, is a static function, which cannot have any uses of this, usable as a receiver-function for any receiver?), we could just allow functions to declare any normal parameter as a this parameter.

Then you can write (Html this) { somethingOnHtml(); } and the name will be looked up in the parameter this. If we combine this with something like #16900, then you can bind an object as a receiver as o -> (this) { .... use methods on this ... }.

(We still have to handle some edge cases with that approach, like cases where an instance method in the lexical scope is not on this).

That approach would not give as nice a syntax because you have to introduce a parameter and write this, not just write the Type:: in front, but instead it allows you to infer the parameter type in the normal way.

I like your proposal. It does not introduce syntactic sugar and new syntax. Ofcourse one has to write (Html this) { ... }, but it looks more straight forward and intuitive.

class Html {
    Body body;

    Body body(void receiver(Body body)) {
        var body = Body();  // create the receiver object
        receiver(body);        // Invoke receiver with receiver object
        this.body = body;
        return body;
    }
}

class Body {
    List<Children> children;

    Div div(void receiver(Div div)) { ... }
    P p(void receiver(P p)) { ... }
}

DSL would look something like this:

html((this) {       // Anonymous function with receiver begins here
    body((this) {
        div((this) {
             // TODO
        });
    });   // calling a method on the receiver object without additional qualifier
});

With higher order functions and optional semicolons:

html (this) {       // Anonymous function with receiver begins here
    body (this) {
        div (this) {
             // TODO
        }
    }   // calling a method on the receiver object without additional qualifier
}

Stumbled upon this thread by accident, was captivated by the discussion, now feel the urge to join in - sorry :)

How about 2-step solution?

Step 1: allow every function/method/operator/constructor in dart to have a magic argument of type InvocationContext. If a function declares this argument, compiler passes it automatically.
Actually,it's a paremetrized type InvocationContext\. What T is for, and how it helps in the issue at hand - we will see shortly

Step 2. Extend the syntax of cascade to allow cascading blocks, like foo..{ code...}
"Code" is whatever we can currently write inside a block or function body - it can be anything,

But: whenever there's a function call inside this block, then - if said function has an InvocationContext argument - compiler passes the context that contains the reference to "foo"
in context.parent

Example:

Html..{
   +Body..(
      +Div..{
         // content 
       };
      +Div(parameters)..{
         // content    
       }
       for (int i=0; i<10; i++) {
          +Div(parameters);
       }
   )
}

Operator unary + can be defined in Div class with parameter {InvocationContext\ context}
and implemented as just
context.parent.addChild(this);

(Note that we don't add any anonymous methods to receiver here)

I think extension methods can be expressed in a similar manner, not sure, It's just a raw idea at this point. (BTW, we discussed InvocationContext earlier, in connection with logging, but it never got much traction then, though I think it's a powerful concept).

Step 2. Extend the syntax of cascade to allow cascading blocks, like foo..{ code...}

"Cascading blocks" with implicit this context is a brilliant idea. With that we need neither InvocationContext (which feels very odd to me) nor receiver methods.

Example:
This is basically with pattern baked into the language.

Html().{
  // Here "this" is "Html" instance on which cascading block was invoked.
  /* implicit this. */body(width: "100%").{ ... } // body is just a method on Html
}

Full example:

class Html {
    Body body;
    Body body({String width}) => this.body = Body()..width = width; 
}

class Body {
    List<Children> children;
    Div div(/*{... params ...} */) { ... }
    P p(/*{... params ...} */) { ... }
}

Usage in DSL with optional semicolons:

Html().{
    body().{
        div(class: "a-box").{
             // TODO
        }
    }
}

We briefly touched upon cascading blocks in this thread https://groups.google.com/a/dartlang.org/forum/#!topic/misc/NDrzmF6UGjQ

It seems Lasse didn't like it. Or maybe I failed to explain what I meant. I also remember that "with" was frowned upon, in every language it showed up I don't remember the specific reasons, but if there are any, then same objections must apply to Kotlin's contraption. One criticism that can be made about it is: the body can see too much inside the object, which is aggravated by the fact that object's properties eclipse the names from the lexical scope, It's easy to inadvertently hit object's method instead of local one. Every change in the class (e.g. addition a new method) has the potential to conflict with some of the anonymous blocks already written by someone. If this is a real concern, then InvocationContext solves the problem.

In fact, InvocationContext has more uses, unrelated to the issue under discussion.

And then, there's a number of purely practical considerations. In your design, you have to define lots of auxiliary functions: e.g. "Body" has to define a function to insert "div", to insert "p", and every other type of element, True, these functions can be inherited from common base class, but the common base class cannot know anything about custom components. In flutter, custom components can nest, there can be Foo with Bar as a child, but Foo doesn't know anything about Bar, so it cannot contain "bar" method.

With InvocationContext, the problem simply doesn't exist, you don't have to write a single line of code to support Bar inside Foo, because InvocationContext parameter gets inherited by Bar constructor from the constructor of HTMLElement, and the rest is automatic.

Another point: consider this

Html().{
    body().{
        for (int i=0; i<10; i++)
            div().{
                 // TODO
            }
    }
}

In this program, it's not quite clear that div gets attached to its parent (body) as a child b/c it looks like a function call rather than "add child" instruction. WIth unary plus, the logic is more explicit.

Html().{
    +Body().{
        for (int i=0; i<10; i++)
            +Div().{
                 // TODO
            }
    }
}

the body can see too much inside the object

Only what is public. Nothing to loose our sleeps over. Also "cascaded blocks" have same problem.

Every change in the class (e.g. addition a new method) has the potential to conflict with some of the anonymous blocks already written by someone.

This same problem is already present inside a method. Adding new methods will eclipse the functions from global scope. This does not prevent people from adding methods though.

void hello() => print("hello");
class User {
  User() => hello();
  void hello() => "Hello from user"; // <= Newly added! Kaboom!
}

Kotlin has receiver methods and extension methods. Have to say, this has never been a problem. Again "cascaded blocks" have same problem.

which is aggravated by the fact that object's properties eclipse the names from the lexical scope, It's easy to inadvertently hit object's method instead of local one

Very careless programming. Never a real problem. This is already the case inside usual methods as mentioned above. "cascaded blocks" have same problem.

And then, there's a number of purely practical considerations. In your design, you have to define lots of auxiliary functions: e.g. "Body" has to define a function to insert "div", to insert "p", and every other type of element, True, these functions can be inherited from common base class, but the common base class cannot know anything about custom components. In flutter, custom components can nest, there can be Foo with Bar as a child, but Foo doesn't know anything about Bar, so it cannot contain "bar" method.

With InvocationContext, you have to implement multiple overloaded methods with different parent types. Dart doesnt support methods overloading yet. Besides, it is hard to know what a child can be added to (usually you wouldn't even have control over that package). It is easier to know what will be added into something. Kinda like add should be in List, not String, int and every other class.

but the common base class cannot know anything about custom components

There should be a Widget base class for widgets and generic addWidget receiver method in Body for custom widgets.

Question 1: What gets passed as InvocationContext?

class Body {
  void operator+(InvocationContext<HtmlWidget> ic) { ... }
}

Html().{
    +Body().{ // <= What do you pass here?
      // ...
    }
}

If I understand right, this gets passed as invocation context? That is pretty cool! So when there is a no this (outside method or in cascade blocks), a method/operator with InvocationContext is disallowed.

Question 2: Abusing unary operators
Abusing unary operators for this is not a good idea. But it does result in a clean syntax.

Question 3:
It is an intrusive and inconsistent change because of the statement below:

allow every function/method/operator/constructor in dart to have a magic argument of type InvocationContext.

Having a method like this:

void something(InvocationContext<Html> ic, var1, var2) { ... }

and calling it like this:

something(var1, var2);

is not consistent.

However, using constructor of child or any other function that returns child to add children is a huge bonus!

If we get just the "cascaded blocks", without any of receiver functions, InvocationContext or higher order functions, we can achieve the DSL like shown below:

class Html {
    Body body;
    Body body({String width}) => this.body = Body()..width = width; 
}

class Body {
    List<Children> children;
    Div div(/*{... params ...} */) { ... }
    P p(/*{... params ...} */) { ... }
}

Html().{
    body().{
        div(class: "a-box").{
             // TODO
        }
    }
}

InvocationContext is a named parameter (not a positional one), so it's neither intrusive nor inconsistent.

void operator+({InvocationContext<HtmlWidget> ic}) { 
    ic.parent.addChild(this); // that's all
}

The only thing we have to know about InvocationContext for this feature to work is that it contains reference to "parent", and this parent has type HtmlWidget. In your example, reference to Html object will be passed as "parent" to "+Body" operator.

Abusing operators is nothing new. E.g. In C++, you have <<. Just a matter of convenience. In natural language, we have lots of overloaded words too.

To clarify, I'm not identifying myself with either of these propositions, be it "with" or "InvocationContext or anything else - just trying to formulate pro/con arguments for them.

The question is whether the feature is aligned with dart's plans for its future evolution. If so, it makes sense to discuss details (e.g. take some example from flutter and encode it in one way and then in another way). Otherwise, such discussion would be premature :)

flutter example:

BEFORE:

new Card(
  color: Colors.white,
  child: new Center(
    child: new Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: <Widget>[
        new Icon(choice.icon, size: 128.0, color: textStyle.color),
        new Text(choice.title, style: textStyle),
      ],
    ),
  ),
);

AFTER:

Card(
    color: Colors.white).{
    +Center().{
        +Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.center).{
            +Icon(choice.icon, size: 128.0, color: textStyle.color),
            +Text(choice.title, style: textStyle),
        }
    }
}

The only change required in the widget library code to support this syntax is: add operator+ in Widget base class. Whether the improvement is sufficient to justify the whole feature - I don't know, but maybe it is. Some feedback from flutter practitioners would help :)

(Nitpick: There is no prefix + operator in Dart. The only overridable prefix operators are ~ and -).

This is not a serious obstacle. It's never late to add a good operator :)
And here we have a good example of use case to justify it.
(But maybe minus is OK, too? Not sure).
Seriously, I find it easier to write and read in this syntax (maybe just me?). And we can use any code inside the block - the problem that templating syntax in angular and elsewhere was trying to solve, with embarrassing results.

I like this, and I think if done right it can solve this case:

List.map((x) => x.foo);

It could also make for nicer tablification:

List.tableify((TableData td) => use(td.isEven, td.isOdd, td.isFirst, td.isLast, td.item, td.rowNumber));

assuming strawman syntax .{}/.=>, those examples become:

List.map(.=> foo);
List.tableify(.=> use(isEven, isOdd, isFirst, isLast, item, rowNumber));

After more thinking, it probably makes sense to separate the "syntax idea" from "implementation idea". There's more than one way to implement it, InvocationContext is just an example, and probably not the simplest example. E.g., if the only use case we have is "adding a child to parent" (or more generally, adding en element to container), then the implementation can be more straightforward: if a class Foo says it implements, say, Container\, then we can write

Foo().{
   +Bar();  // unary plus as synonym to parent.addChild(Bar())
   +Bar();
}

The notation can target just a single use case, but if this use case is all we have then there's no point to generalize it.

It very well might be that child-parent (or element-container) relationship is so fundamental to programming that it warrants a special syntax?

After playing with different variants proposed above ad nauseum, came to hate all of them. Too much punctuation, all these baroque (){},;., my head started spinning from these architectural excesses.
Here's a new, radically improved, version, which I love with every fiber of my being (so far):

Card{
    .color= Colors.white;
    +Center{
        +Column{
            .mainAxisSize = MainAxisSize.min;
            .crossAxisAlignment = CrossAxisAlignment.center;
            +Icon(choice.icon, size: 128.0, color: textStyle.color);
            +Text(choice.title, style: textStyle);
        }
    }
}

No "this" inside the block - instead, there's just dot.
This can be interpreted as an invocation of constructor with relaxed syntax (you can write any code in the block, but have to initialize everything required by class definition).

Adding some details to my version of proposal.

New syntax of constructor invocation proposed. Invocation syntax:

// for default constructor
ClassName{
   // initialization block
}
// for named constructor
ClassName.constructorName{
   // initialization block
}

Suppose we have a constructor ClassName({T1 arg1, T2 arg2}).
Compiler interpets the initialization block as if it had local variables named ".arg1", ".arg2",... ".argN" declared in the beginning of the block.

ClassName{
   T1 .arg1;
   T2 .arg2;
   // the rest of initialization block
}

Initialization block can contain arbitrary program, the goal of which is to assign values to .argN variables
At the end of the block, compiler inserts an invocation of real constructor ClassName(arg1: .arg1, arg2:.arg2);

Important point here is that initialization block cannot directly access the members of the class. It operates at the level of intermediate variables .arg1, ... .argN.
The reason is: when the block gets executed, the instance doesn't yet exist. For it to exist, the constructor should be called, which is exactly what happens when the block completes.

Dot by itself does not have any meaning (in particular, we can't refer to the instance under construction using "." expression).

If the constructor defines one of the parameters using @children annotation, then corresponding intermediate (dotted) variable is "declared" as a (growable) List of appropriate type (e.g.
List\). If functions as a normal variable inside the block, but supports additional sugar: +expr is interpreted as list.add(expr).

Similarly, if one of the parameters is defined with @child annotation, compiler supports +expr syntax, which is simply equivalent to the assignment to corresponding dotted variable.
(@child and @children are mutually exclusive in the list of parameters).

Open issues:

  1. what to do with positional parameters of the constructor, if any? Declare them as dotted names?
  2. when constructor parameter is optional, then corresponding dotted variable has to be nullable?
  3. "child" variable should be protected from re-assignment somehow (+ operator can be invoked only once).

Another example:

BEFORE:

return new Container(
  width: _kDotSpacing,
  child: new Center(
    child: new Material(
      color: color,
      type: MaterialType.circle,
      child: new Container(
        width: _kDotSize * zoom,
        height: _kDotSize * zoom,
        child: new InkWell(
          onTap: () => onPageSelected(index),
        ),
      ),
    ),
  ),
);

AFTER:

return Container{
    .width = _kDotSpacing;
    +Center{
        +Material{
            .color = color;
            .type = MaterialType.circle;
            +Container{
                .width = _kDotSize * zoom;
                .height = _kDotSize * zoom;
                +InkWell(
                    onTap: () => onPageSelected(index)
                )
            }
        }
    }
};

If dart ever comes up with an idea of how to make semicolons optional, this will remove all the remaining noise.
(With the old format, optional semicolons won't help at all b/c commas)

Another example:

BEFORE:

return new Container(
  width: _kDotSpacing,
  child: new Center(
    child: new Material(
      color: color,
      type: MaterialType.circle,
      child: new Container(
        width: _kDotSize * zoom,
        height: _kDotSize * zoom,
        child: new InkWell(
          onTap: () => onPageSelected(index),
        ),
      ),
    ),
  ),
);

AFTER:

return Container{
    .width = _kDotSpacing;
    +Center{
        +Material{
            .color = color;
            .type = MaterialType.circle;
            +Container{
                .width = _kDotSize * zoom;
                .height = _kDotSize * zoom;
                +InkWell(
                    onTap: () => onPageSelected(index)
                )
            }
        }
    }
};

If dart ever comes up with an idea of how to make semicolons optional, this will remove all the remaining noise.
(With the old format, optional semicolons won't help at all b/c commas)

Excellent kotlin like example! @tatumizer
I like this DSL more than JSX in the JS world.

I also prefer swift to implememt this feature (with receiver) too, haha.

But dart extension most like swift extension that without where limit than kotlin at 2020-05-08.

Could add this feature (where limit) to dart to make it more powerful than like a Semi-finished Product?

The below swift extension example that reimplement the QuickCheck library in haskell to show where limit :

public struct Array<Element> {
}

// like extension name in dart
public protocol Arbitrary {
    static func arbitrary() -> Self
}

// like extension name in dart
public protocol Smaller {
    func smaller() -> Self?
}

extension Array: Arbitrary where Element: Arbitrary {
    public static func arbitrary() -> [Element] {
        let randomLength = Int.random(in: 0...50)
        return tabulate(times: randomLength) { _ in
            return Element.arbitrary()
        }
    }
}

extension Array: Smaller where Element: Arbitrary {
    public func smaller() -> [Element]? {
        if !self.isEmpty {
            return Array(self.dropFirst())
        }
        return nil
    }
}

public func check<A: Arbitrary & Smaller>(message: String, size: Int = 100, prop: (A) -> Bool) -> () {
    for _ in 0..<size {
        let value = A.arbitrary()
        if !prop(value) {
            let smallerValue = iterateWhile(condition: { !prop($0) }, initialValue: value) {
                $0.smaller()
            }
            print("\"\(message)\" doesn't hold: \(smallerValue)")
            return
        }
    }
    print("\"\(message)\" passed \(size) tests.")
}

Now use below code example to quicktest your qsort (QuickSort) function :

import Swift_QuickCheck

public func qsort(_ array: [Int]) -> [Int] {
    if array.isEmpty {
        return []
    }
    var arr = array
    let pivot = arr.removeFirst()
    let lesser = arr.filter {
        $0 < pivot
    }
    let greater = arr.filter {
        $0 >= pivot
    }
    return qsort(lesser) + [pivot] + qsort(greater)
}

check(message: "qsort should behave like sort") { (x: Array<Int>) in
      return qsort(x) == x.sorted(by: <)
}

Output:

"qsort should behave like sort" passed 100 tests.

Now using dart to reimplement maybe like that :

extension Arbitrary<Element: Arbitrary> on Array<Element>  {
   //  ...
}
Was this page helpful?
0 / 5 - 0 ratings