0

I have an interface that looks like this.

interface Value {
  public function accept<T>(ValueVisitor<T> $visitor): T;
}

Since there is only one method, I want to write a class which converts a closure into an instance of Value.

final class ClosureValue implements Value {
  public function __construct(
    private (function<T>(ValueVisitor<T>): T) $f
  ) {}

  public function accept<T>(ValueVisitor<T> $visitor): T {
    $f = $this->f;
    return $f($visitor);
  }
}

However, the <T> in the type function<T>(ValueVisitor<T>): T is a syntax error. No matter where I put the <T>, it wont parse.

How can I write this in Hack?

Jesse
  • 6,725
  • 5
  • 40
  • 45
  • Forgive my lack of imagination, but what can your generic closure `$f` even do, since it can't capture `T`-typed values from its environment? How is it interacting usefully with `ValueVisitor`? – concat Nov 08 '16 at 22:57
  • `ValueVisitor` has methods that return `T`s, so a function `(function (ValueVisitor) :T)` must return a `T` and the only means it has to do that is by calling methods of the `ValueVisitor` given to it. – Jesse Nov 10 '16 at 01:01
  • I'm curious just how many different combinations of method calls you intend to make on `ValueVisitor`, but in general this seems reasonable. Your best bet is probably a feature request to the Hack team. (Personally, I'm also hoping anonymous classes eventually get implemented, which could help you here too) – concat Nov 12 '16 at 16:58
  • Yep, here's the issue for anonymous generic functions https://github.com/facebook/hhvm/issues/7451 and anonymous classes https://github.com/facebook/hhvm/issues/6039. – Jesse Nov 13 '16 at 11:07

2 Answers2

-1

Right now I can't try, if its working but this might works:

final class ClosureValue<T> implements Value {
    public function __construct(
        private (function(ValueVisitor<T>) : T) $myF
    ) {

    }


    public function accept(ValueVisitor<T> $visitor) : T {
        $fn = $this->myF;
        return $fn($visitor);
    } 
}
Zoltán Fekete
  • 504
  • 1
  • 6
  • 22
  • `ClosureValue` would become a value which can only accept visitors producing values of type `T` (decided on construction), and the `accept` method is no longer generic and is therefore incompatible with the `accept` method of `Value`. – Jesse Aug 13 '16 at 13:51
-1

Its working for me fine...

classes.hh

<?hh // strict

class ValueVisitor<T>
{
    protected T $value;
    public function __construct(T $new) { $this->value = $new; }
    public function get(): T { return $this->value; }
}

interface Value { public function accept<T>(ValueVisitor<T> $visitor): T; }

final class ClosureValue<T> implements Value {
    public function __construct(
    private (function(ValueVisitor<T>) : T) $myF
) {

}

public function accept(ValueVisitor<T> $visitor) : T {
    $fn = $this->myF;
    return $fn($visitor);
}

// main.hh

<?hh // strict

class MyClass
{
    public function __construct(
        protected string $myVal
    ) { }

    public function getMyVal(): string { return $this->myVal; }
}

function main<T>() : void
{
    $visitor = new ValueVisitor(12);
    $val = new ClosureValue(function(ValueVisitor<int> $f): int {
        return $f->get();
    });

    echo $val->accept($visitor);


    $visitor2 = new ValueVisitor('Foo');
    $val2 = new ClosureValue(function(ValueVisitor<string> $f): string {
        return $f->get();
    });

    echo $val2->accept($visitor2);

    $visitor3 = new ValueVisitor(new MyClass("asd"));
    $val3 = new ClosureValue(function(ValueVisitor<MyClass> $f): MyClass {
        return $f->get();
    });

    print_r($val3->accept($visitor2));
}

index.hh

<?hh // partial    

require 'classes.hh';
require 'helpers.hh';
require 'main.hh';

main();
Zoltán Fekete
  • 504
  • 1
  • 6
  • 22
  • This isn't how visitors work. `ValueVisitor` doesn't mean a visitor for values of type `T`, it means a visitor producing a value of type `T`. The type of values being visited are the parameters to the methods of `ValueVisitor`, not `T`. You can read about the visitor pattern here: https://en.wikipedia.org/wiki/Visitor_pattern – Jesse Sep 03 '16 at 14:56
  • You asked help for syntax error, so my answer is only for resolving your syntax error. And yet it solves... – Zoltán Fekete Sep 12 '16 at 08:25
  • Fixing a syntax error by replacing it with code that doesn't work isn't helpful. – Jesse Sep 12 '16 at 08:50