Make classes callable as functions. Remove user-defined function object boilerplate code.

Propose new features and changes
iseahound
Posts: 610
Joined: 13 Aug 2016, 21:04
GitHub: iseahound

Make classes callable as functions. Remove user-defined function object boilerplate code.

07 May 2020, 19:11

There is no reason to make use of this complex boilerplate just to have class1.class2() execute properly.

class1.class2(1)

Code: Select all

; This example requires the FunctionObject class above in order to work.
class class1 {
    class class2 extends FunctionObject {
        Call(self, a) {
            MsgBox % a
        }
    }
}

class FunctionObject {
    __Call(method, args*) {
        if (method = "")
            return this.Call(args*)
        if (IsObject(method))
            return this.Call(method, args*)
    }
}
Reasons why this is bad:
  • Boilerplate is unfriendly to newbies. Why 2 classes?
  • Function Objects should be first-class. This boilerplate demonstrates they are not.
  • Newbies start out using classes as more of a tool to organize their functions. By letting them replace their functions with function objects, they can more easily understand classes.
A gentle reminder that AutoHotkey is a procedural programming language at heart.
iseahound
Posts: 610
Joined: 13 Aug 2016, 21:04
GitHub: iseahound

Re: Make classes callable as functions. Remove user-defined function object boilerplate code.

07 May 2020, 20:03

Again the reason why this won't occur is because @lexikos refuses to give up "load-time validation and optimization of functions".
One idea (that I thought had been brought up already, but I'm not sure now) is to declare that a variable can be called. This would allow load-time validation and optimization of functions to be retained. For example:
from https://www.autohotkey.com/boards/viewtopic.php?t=64712&start=20&p=295151

and goes on to reinvent static typing.

It really comes down to when lexikos finally decides it's better to drop this light pretense at static typing. Currently the separation of function and variable names into different lists; the separation of [data], .methods(), and .properties is static typing albeit via syntax.

There's only two realistic options:
  1. Keep runtime error checking and embrace static typing by making it truly explicit. Ex. var foo := "bar" like Javascript.
  2. Embrace dynamic typing, give up runtime error checking and optimization in favor of lazy evaluation. Ex. foo could evaluate to an object and foo() could call a method within that object.
Helgef
Posts: 4459
Joined: 17 Jul 2016, 01:02
Contact:

Re: Make classes callable as functions. Remove user-defined function object boilerplate code.

08 May 2020, 01:18

Hi.
There is no reason to make use of this complex boilerplate
I agree ;)
the reason why this won't occur is because @lexikos refuses to give up "load-time validation and optimization of functions".
There is no load-time validation or optimisation of x.y().

I'm not sure if this suggestion is for v1 or v2, but for v2, what you suggest is in effect to revert to the conflation of properties and methods. I disagree with such proposals.

Cheers.
iseahound
Posts: 610
Joined: 13 Aug 2016, 21:04
GitHub: iseahound

Re: Make classes callable as functions. Remove user-defined function object boilerplate code.

08 May 2020, 10:07

Nice to see you Helgef! My primary suggestion is for v1.

In v2 the separation of properties and methods has already failed.
  • arity-null .fn vs. arity-0 .fn() It comes down to informing a newbie that .length and .length() are two different concepts.
  • object -access . vs. function composition . Statements like a.b(x).c(y) are inherently ambiguous depending on whether c() is a method of b or if c() is a method of the return value of b()
Here's a motivating example:
Vis2.Google.OCR().toList() Takes an image and returns a object and calls its built-in method to return a list.
Vis2.Google("api-key").OCR().toList() Sets an API key and accesses the subclass method to return a object and calls its built-in method to return a list.

Code like this works well in v1, but it's clear that a lot of the ambiguity stems from the multi-use of the .. Separating methods and properties is fine, but reduces user friendliness.

Suggested solutions:
  • Allow inference when accessing objects. In order of priority: syntax type, .method(), .property, [data]. For example calling .length checks for a length property first, then returns a method (if found) and then data. This will 100% make the language easier to use. Using the correct syntax will always be preferred as it will be faster.
  • Prioritize . as object access. In order of priority: subclasses with call() methods, methods inside the class, methods inside the return object, looping here. Function composition should be prioritized with a compose function possibly as compose(object, "method1", "method2"). This adheres to a point-free style and is similar to what sirksel mentioned in this thread. The version I am suggesting is an overload of the normal compose(fn1, fn2, fn3) or compose("fn1", "fn2", "fn3") depending on your syntax preference.
Helgef
Posts: 4459
Joined: 17 Jul 2016, 01:02
Contact:

Re: Make classes callable as functions. Remove user-defined function object boilerplate code.

08 May 2020, 12:27

Nice to see you too iseahound :).
My primary suggestion is for v1.
OK, I won't derail this with anything v2 related then. I'm sure your suggestion is suitable for v1 :).

Cheers.
lexikos
Posts: 7057
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: Make classes callable as functions. Remove user-defined function object boilerplate code.

22 May 2020, 17:44

iseahound wrote:
07 May 2020, 19:11
There is no reason to make use of this complex boilerplate just to have class1.class2() execute properly.
1. The purpose of the "boilerplate" was to show how to recreate a function, not to make anything under the sun callable, and certainly not specifically to make classes callable.
2. The "complex" boilerplate code is only necessary in v1, where these changes cannot be made. Just use the Call method in v2.
3. There is no reason (provided in your post) to conflate function calling with instantiation.
Why 2 classes?
Again, this is only for v1.
1. Code reuse. Do you want to redefine all of the "complex" boilerplate code in every callable class? :roll:
2. In v1, meta-functions must be defined in a base object, so if you want __Call to be invoked for the class, it must not be in the class itself.
Function Objects should be first-class.
That means nothing to me, without reasons or an explanation. I see not why they should be first-class, nor how making all (or just nested) classes behave as function objects is in line with that.
Newbies start out using classes as more of a tool to organize their functions. By letting them replace their functions with function objects, they can more easily understand classes.
I don't buy it.

Anyone can understand the concept of a container as an organizational tool. Put the function into a class, it becomes a method, not the class itself.

Return to “Wish List”

Who is online

Users browsing this forum: No registered users and 10 guests