class BaseFunction {
  static #allowInstantiation = false;

  constructor(...args) {
    if (!BaseFunction.#allowInstantiation) {
      throw new Error(
        "Why are you trying to use 'new'? Classes are so 2015! Use our fancy 'run' method instead!"
      );
    }
    for (const [name, validator] of this.parameters()) {
      this[name] = validator(args.shift());
    }
  }

  parameters() {
    return [];
  }

  body() {
    return undefined;
  }

  static run(...args) {
    BaseFunction.#allowInstantiation = true;
    const instance = new this(...args);
    BaseFunction.#allowInstantiation = false;
    return instance.body();
  }
}

class Add extends BaseFunction {
  parameters() {
    return [
      ["a", (x) => Number(x)],
      ["b", (x) => Number(x)],
    ];
  }

  body() {
    return this.a + this.b;
  }
}

console.log(Add.run(5, 3)); // 8



    • Ephera@lemmy.ml
      link
      fedilink
      arrow-up
      11
      ·
      edit-2
      1 day ago

      Yep, some code examples from the official documentation. This:

      printPersons(
          roster,
          (Person p) -> p.getGender() == Person.Sex.MALE
              && p.getAge() >= 18
              && p.getAge() <= 25
      );
      

      …is syntactic sugar for this:

      interface CheckPerson {
          boolean test(Person p);
      }
      
      printPersons(
          roster,
          new CheckPerson() {
              public boolean test(Person p) {
                  return p.getGender() == Person.Sex.MALE
                      && p.getAge() >= 18
                      && p.getAge() <= 25;
              }
          }
      );
      

      …which is syntactic sugar for this:

      interface CheckPerson {
          boolean test(Person p);
      }
      
      class CheckPersonEligibleForSelectiveService implements CheckPerson {
          public boolean test(Person p) {
              return p.gender == Person.Sex.MALE &&
                  p.getAge() >= 18 &&
                  p.getAge() <= 25;
          }
      }
      
      printPersons(roster, new CheckPersonEligibleForSelectiveService());
      

      The printPersons function looks like this:

      public static void printPersons(List<Person> roster, CheckPerson tester) {
          for (Person p : roster) {
              if (tester.test(p)) {
                  p.printPerson();
              }
          }
      }
      

      Basically, if you accept a parameter that implements an interface with only one method (CheckPerson), then your caller can provide you an object like that by using the lambda syntax from the first example.

      They had to retrofit lambdas into the language, and they sure chose the one hammer that the language has.

      Source: https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

      • mbtrhcs@feddit.org
        link
        fedilink
        arrow-up
        9
        ·
        1 day ago

        That’s not quite right. In bytecode, lambdas are significantly more efficient than anonymous class instances. So while the lambda implementation is semantically equivalent, characterizing it like you have is reductive and a bit misleading.

  • NewDark [he/him]@hexbear.net
    link
    fedilink
    English
    arrow-up
    5
    ·
    1 day ago

    I’m pretty sure this post is designed to kill the soul. I am made slightly worse for witnessing this abortion of an implementation and I will never be quite the same again.