Changes to %fn%(), fn.call() or func('fn') syntax?

Discuss the future of the AutoHotkey language
sirksel
Posts: 53
Joined: 12 Nov 2013, 23:48

Changes to %fn%(), fn.call() or func('fn') syntax?

20 May 2019, 17:02

Many thanks to @lexikos for all the work he has done to enable fat arrow notation (e.g., fn(x,y) => x*y and x => x*2) and method/property shorthand (e.g., property[] => expr()). It takes Func.Bind() to a whole new level, and really enables much more efficient functional programming (e.g., map, filter, compose, pipe, transduce, etc.). I don't think fat arrow in AHK allows blocks, but multi-statement makes most functional constructs possible anyhow. That said, a couple small sticking points remain that make functional programming in AHK a little less streamlined/clear than it could be:

1. Function objects can only be called as fn.call() or %fn%() rather than fn(). Unlike a lot of other languages that have first-class functions, AHK seems to require that every function composition, partial, etc. (anything returned as a function/boundfunc/closure object) must be called in this more roundabout way.

2. Explicitly defined and built-in functions can't be referenced/passed without a Func() wrapper creating the function object. It makes for slightly awkward pipe/compose constructs when mixing defined functions with other intermediate (and possibly non-global) function objects, especially when trying to compose in a pointfree style. For example: strbaz := compose(func('strsplit'), strbar, func('strupper'), strfoo). I've also tried doing this: strbaz := compose('strsplit', strbar, 'strupper', strfoo), then checking param type and auto-wrapping. It reads slightly better, especially when the composition is nested or more complex, but it's a bad option because it's more error-prone and bypasses the interpreter optimizations.

Any thoughts? Are these design decisions that you plan to preserve in v2? Are they possibly part of your consideration for changes, along the lines of the other %% discussions in the Objects preview thread?
lexikos
Posts: 6652
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: Changes to %fn%(), fn.call() or func('fn') syntax?

22 May 2019, 04:31

I'm sure this has come up multiple times, but I wasn't able to find a good topic to reference.

1. %% or .Call is required when calling a value (typically contained by a variable), regardless of the type. What you want is for xxx() to permit both function names and variable names without any differentiation. This requires combining the two into one namespace, which implies that you can no longer have a function and a variable with the same name in the same scope. I believe these are the main drawbacks:
  • Assignments accidentally overwriting functions. This can be mitigated by making function identifiers read-only (I mention it because it's a common issue in some languages, and would be even more so here due to case insensitivity).
  • Variables accidentally shadowing functions by the same name. If the variable does not contain a function, this would cause a runtime error when the function call is attempted. If the variable does contain a function but not the one the author intended to call, the error is harder to detect.
  • The reduction in load-time error checking. For example, if an author makes a typo in the function name, it might be difficult to catch the error at load time since the author might have been intending to call a variable. (Aside from the above problems, load-time validation of function parameters can still take place, provided that it is not possible to overwrite a function at runtime.)
2. Generally Func returns the function itself; the same object that a static call such as MsgBox() references. Even if you were able to reference the function directly by name, what you would get is exactly the same. There is no wrapping or creating, except in the case where the function contains upvars, where Func creates a Closure referencing the original function and captured variables. (The current implementation permits a nested function to be called directly without the overhead of creating a closure.)


I had written the following in v2-thoughts, but hadn't updated it online (for no particular reason):


Detecting mispelled function names at load time is a useful feature of the language, but currently only applies to direct calls. References such as Func("name") or "name", if mispelled, will only be detected when the script attempts to call them (which might not be where they are referenced).

Func("name") is optimized (in v2) to resolve at load time, but cannot raise a load time error when the function does not exist because it is not an error. For instance, name can be defined in an optional #include *i, and Func is how it would be resolved to be called. If it raised a load time error, this would not work:

Code: Select all

    if f := Func("name")  ; ← load time error
        f.Call()
Nor would this:

Code: Select all

    if IsFunc("name")
        MyRegisterEvent(Func("name"))  ; ← load time error
The most obvious solution is to add new syntax for a function reference which would be caught as an error at load time if the function does not exist.
  • fincs suggested @name, as in OnExit(@ExitHandler) or greet := @MsgBox.Bind("Hello").
  • Another idea is Func'name', as in OnExit(Func'ExitHandler') or greet := Func"MsgBox".Bind("Hello"). Although not currently valid, it might be difficult to visually distinguish from auto-concat.
iseahound
Posts: 460
Joined: 13 Aug 2016, 21:04
GitHub: iseahound

Re: Changes to %fn%(), fn.call() or func('fn') syntax?

05 Aug 2019, 18:18

I don't know if this is naïve but would it be possible to "lift" the variable into the function namespace? There already exists some oddly specific behavior: namely a function and a class can have the same name, but if the function and the class are nested inside a bigger class, this fails.

Scenario #1

Code: Select all

s()

; You can comment this out
s() {
   MsgBox % A_ThisFunc
}

; But class s can never be called...
class s extends functor {
   call(terms*) {
      MsgBox % A_ThisFunc
   }
}

class functor {
   __Call(self, terms*) {
      if (self == "")
         return this.call(terms*)
      if IsObject(self)
         return this.call(self, terms*)
   }
}
Scenario #2

Code: Select all

namespace.s()

class namespace {

   ; static s := A_ThisFunc

   ; Either comment out function s()
   s() {
   	MsgBox % A_ThisFunc
   }

   ; Or comment out class s
   class s extends functor {
      call(terms*) {
         MsgBox % A_ThisFunc
      }
   }

}

class functor {
   __Call(self, terms*) {
      if (self == "")
         return this.call(terms*)
      if IsObject(self)
         return this.call(self, terms*)
   }
}
In Scenario #1 variable space and class space are merged together (classes can be overwritten with simple assignment!) and function space is separate. However in Scenario #2, they start to mix together. Specifically when operations are conducted inside a nested class, only one of the three is permitted: the variable s, the function s() or the class s.

One solution to this problem would be to keep the existing variable and function spaces separate, and letting the class space be the "push-out" of the two spaces. In other words if we imagine the spaces as lists with a check mark next to them, the variable s has a check mark in the column "isVariable?", the function s() has a check mark in the column "isFunction?", and the class s has a check mark in both the variable and function columns. Checking for errors would allow a function and variable declaration of the same name, but disallow a class and a variable of the same name, and disallow a class and a function of the same name. Instead, classes could be called with className() exactly like a function - something that currently is not possible right now. Finally it would standardize behavior in Scenario 1 & 2, things inside nested classes aren't treated differently from those outside.

As a side note: Partial functions would be both variables and functions - a boundFunc could be called boundFunc() and referenced as boundFunc. Classes would have a additional "super" flag that boundfuncs lack, allowing them to be visible anywhere. (super lexical scoping?)

Sorry if this doesn't make any sense.
User avatar
nnnik
Posts: 4274
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Changes to %fn%(), fn.call() or func('fn') syntax?

06 Aug 2019, 01:18

A function inside a class doesnt exist. A function when defined inside a class is a method. Variable space does not exist within classes - they are object members and object space.

None of that is a good decision. Why does object space differ so strongly from the script space? Why is there no common mechanism to just address the outer space between the 2? Why do object keys differ so strongly from normal variables?

I agree with you that functions need to get pulled down from their high horse and get inserted into normal variable space.
This also wouldn't change current behavior if we made specific entries into the variable space read only.
For example function and class entries.

A while back I argued against making classes read only but I changed my mind. Overwriting a class is not that important.
Classes could also take on the role of a namespace - instead of creating a new mechanic with new operators and new implications etc...
Class space should be entirely consistent with script space on most things (e. g. It doesnt need to support labels, hotkeys, preprocessor instructions, A_variables...)
Recommends AHK Studio
lexikos
Posts: 6652
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: Changes to %fn%(), fn.call() or func('fn') syntax?

10 Aug 2019, 00:07

iseahound wrote:
05 Aug 2019, 18:18
... but if the function and the class are nested inside a bigger class, this fails.
Not in the next alpha. Like with Objects.ahk (but without the restrictions imposed on class definitions by the current alpha), properties and methods are separate. Static members and instance members are also separate. A nested class, instance property, static method and instance method can all coexist in the same class with the same name.
There already exists some oddly specific behavior:
It is not that specific. A function and variable can coexist, but in the current alpha and v1, a method and property cannot coexist.
nnnik wrote:
06 Aug 2019, 01:18
This also wouldn't change current behavior if we made specific entries into the variable space read only.
For example function and class entries.
If a script never creates a variable (by assignment or merely by reference) with the same name as a function, that script's behaviour would not change. If a variable and a function existed with the same name, the script would no longer work; it would either fail to execute, or execute incorrectly. So "wouldn't change current behavior" is either incorrect or not particularly meaningful.

Making function-variables read-only solves one problem: accidental overwriting of functions by assignment.


When an undefined function is encountered at load-time, the possible responses are:
  • Attempt to include a file from stdlib to pull in a function definition. On failure, do either of the following.
  • Raise an error.
  • Do nothing (until run-time).
Combining the namespaces does not necessarily imply that there is a variable for every function definition. A name could be bound to either a variable or a function. An identifier for which no function definition exists could be either a variable or an undefined function (which may or may not be a variable).

If they can't be differentiated based on syntax, there are some options.
  1. Assume it is a variable which might be assigned a function object later. Valuable load-time error detection is lost. Auto-include could be attempted first, but that could be problematic.
  2. If auto-include fails, raise an error. Flexibility is reduced - variables still cannot be called directly.
  3. A mixture, depending on whether the variable is declared (could be a normal declaration or a new kind of declaration which shows the intent). I suppose this implies more complexity, and some compromises (less convenience and more clarity than #1, but still less clarity than syntax dedicated to function references).
  4. A mixture, depending on whether an assignment is detected somewhere. I suppose this has a balance of convenience, flexibility and error-checking capability, but increases complexity and lacks clarity.
User avatar
nnnik
Posts: 4274
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Changes to %fn%(), fn.call() or func('fn') syntax?

10 Aug 2019, 04:16

Thanks for the thorough explanation. I missed a few points while making my post.

The current behavior will change. Im not quite sure what I meant with that note. I think it was supposed to say something like "functions still can't get overwritten by assignments".
Im not convinced that keeping the auto-include setting active is good practice - nonetheless it adds value to the language imo. If that value outweighs the costs that it introduces is another question.

We have the goals of: Allowing normal functions to work, doing runtime/loadtime error checking, auto-including and finally allowing dynamic function references to be called like normal functions.
  1. Allowing normal functions to work is obviously priority nr. 1
    Making some variables read only would ensure this to some degree - (it would also help with some other problems)
  2. runtime error checking is my next priority. If something goes wrong it should at the very least be detected at runtime.
    Just saying nothing is not an option imo.
  3. auto-include and calling dynamic functions like normal ones are tied for this spot. I think calling dynamic functions like normal ones is slightly more important.
    But I dont think its enough to place it above auto-including. Both should still work. Since they currently conflict in any of the alternatives you have shown.
  4. load time error checking it's nice - but most of the language doesn't have load time error checking.
    Keeping it here and favoring it over a new possible syntax would be a bad decision imo.
If we imagine a language that ideally covers all of these priorities in order:
Checks at load time to some degree in a function fool absolutely cannot be a dynamic call and cannot be from a dynamic include.
When encountering the call loads the auto-include or calls the dynamic reference stored/throws an error if an assignment has been made to the variable but it didnt result in a function reference.
Throws an error if no auto-include was possible.

Sadly that conflicts with the current code of AHK v2 (judging from what you said). Since includes need to be included right from the start from the script.
The interpreter would have to evaluate whether that dynamic call is intended to be a dynamic call or call a function in an auto-include before it can fully evaluate that.
You can create code that can make good guesses but in the end %var% is what would break any serious attempt at doing so.
Also I can imagine that that code would be a nightmare to maintain.

Unless something changes with the foundations of the language, this suggestion will have serious side-effects that cannot be mitigated easily.
So in the end "not in v2" is how we could summarize this.
Recommends AHK Studio
iseahound
Posts: 460
Joined: 13 Aug 2016, 21:04
GitHub: iseahound

Re: Changes to %fn%(), fn.call() or func('fn') syntax?

10 Aug 2019, 10:14

I’m still in favor for keeping variable space and function space separate for variables and functions respectively. Function objects should exist across both spaces with one space being equal to referencing the functor and the other being equal to executing or calling the functor. I think other languages resort to lazy evaluation in this case. Yes there probably is not a satisfying low complexity form of run time checking.
sirksel
Posts: 53
Joined: 12 Nov 2013, 23:48

Re: Changes to %fn%(), fn.call() or func('fn') syntax?

01 Oct 2019, 04:45

Based on the discussion so far, it seems unlikely we'll ever be able to call a %myfunctor%() in the same way as a myfunction(). However, I thought I recently read somewhere (although I'm not finding it now), that Lexikos might be considering making .Call() the default method. Is that still a likely outcome or the most recent thinking? If so, does that mean a call like myfunctor() would then work?
lexikos
Posts: 6652
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: Changes to %fn%(), fn.call() or func('fn') syntax?

02 Oct 2019, 03:59

I don't know what you read, but Call is the default method. If you "call" the object itself, Call is the method that executes.

From memory, this applies to:
  • All cases where AutoHotkey calls a function object in response to an event, such as SetTimer, Hotkey, etc.
  • Function objects being called as methods. In v1, the "method name" was actually the target object; i.e. this.m() -> fn := this.m, fn[this]().
  • Calling objects as functions through the COM interface, such as from JScript.
  • %Fn%().
In v1, the default method was fn[""]() or fn.(), with the exception of fn[this]().


I'm still considering options. For instance, I personally wouldn't be concerned about losing auto-includes. Being explicit adds clarity. With #Include <>, the library can still be in any one of the three library locations. Auto-include doesn't permit for multiple versions of a library to co-exist, since the filename must match the function name or prefix. It might even be seen as a form of namespace pollution - the author might merely be trying to call a different function not from the library (e.g. having used the wrong name, made a typo or forgotten to define or #include it) or function reference/variable (whether or not the author has used the right syntax).

And it doesn't support class libraries.

Typically in "modern" scripting languages, one is explicit both about including specific modules and whether/which names are imported into the current namespace.
sirksel
Posts: 53
Joined: 12 Nov 2013, 23:48

Re: Changes to %fn%(), fn.call() or func('fn') syntax?

02 Oct 2019, 08:54

Thanks for clarifying, Lexikos. That makes sense now that I think about it more. Glad to hear you're still considering options. Since I initiated the thread, I thought maybe I'd just explain a little better the reasons or functional-programming use cases for what I've advocated -- namely (1) being able to call either an explicit or derived function with the same syntax myfunc() always, rather than sometimes %myfunc%() and (2) being able to reference either explicit or derived functions in a parallel way without explicitly creating a function object (e.g., myfunc always rather than sometimes Func("myfunc") or ()=>myfunc()). I do understand there are downsides to the namespaces, includes, load-time vs. runtime checking, etc... and you and others have explained these well above.

You've made such enormous improvements to AHK with true Array/Map support, fat-arrow notation, terse single-expression function syntax, etc. that it has become a great language to use/teach functional programming in a practical way. As you know, applications like macros/automation lend themselves nicely to functional style, since they have lots of callbacks for buttons, timers, etc., as well as terse code snippets for hotkeys, etc. I've created a functional library containing standard implementations of map, filter, reduce, fold, take, compose, pipe, curry, etc., which I've now been using in v2 for almost a year. FP works great in AHK, but the syntax can become a little convoluted at times -- primarily for the two "parallelism" reasons mentioned above. Here are a few examples of where that comes into play:
  1. One has to remember/differentiate which functions are derived/curried vs. explicitly defined in order to call them. In non-FP code, derived functions are probably used much less often than explicitly defined functions. In an FP approach, where most functions are derived from other functions, one must be almost indifferent between them. As such, this error of %myfunc%() vs. myfunc() mismatch is probably my most frequent syntax error. Also, but less importantly, %myfunc%() is harder to type and harder to read, especially if you've got a lot of these in your code.
  2. When creating derived functions that are partially applied, I get a lot of this in my code: Func("explicitfn").Bind(x) or y=>%derivedfn%(x,y) -- or sometimes even y=>explicitfn(x,y) and derivedfn.Bind(x), to minimize the Func("") and %% requirements. It would be great to be able to define derivative functions in a parallel way, say for example, when currying a function, to be able to say: explicitfn_curried := curry(explicitfn) or derivedfn_curried := curry(derivedfn). You could then call any of them with the same syntax, without having to remember which is explicit or derived, whether it be explicitfn(x,y), derivedfn(x,y), explicitfn_curried(x,y), or derivedfn_curried(x,y). I use a curry function today that creates dynamic partials, but as noted above, the parallel structure isn't quite there.
  3. When writing FP, I try to write as much as possible in a point-free style, using derived functions created with compose or pipe. When I started this thread, I highlighted this example and the issues the lack of parallelism poses in a chain of composed functions. Even in simpler non-composed functional parameters, I'm noticing that parallelism of references would make point-free style possible and aid in clarity. For example, if I'm using a standard implementation of map to apply a function, say StrUpper, over an Array, I want to be able to write (using point-free style) map(StrUpper, mylist). Instead I end up writing map(Func("StrUpper"), mylist) or map(x=>StrUpper(x), mylist). Neither is ideal, as they're both harder to read and type -- and the latter creates an unnecessary lambda and doesn't take advantage of the Func() optimizations.
I realize functional programming isn't for everyone, but -- whether it was an intentional design decision or not -- you've created an amazing language for it here. The fat-arrow syntax and in-built capabilities seem nearly perfect for FP applications, except for this small issue of parallelism in reference/calling of derived/explicit functions. Many thanks, Lexikos, for all the careful thought and tireless effort you continue to put into this!

EDIT: Tried to make language more precise to clarify that I'm asking about the way we call function/callable objects more generally, not just user-defined functors.
Last edited by sirksel on 04 Oct 2019, 12:59, edited 1 time in total.
swagfag
Posts: 2985
Joined: 11 Jan 2017, 17:59

Re: Changes to %fn%(), fn.call() or func('fn') syntax?

02 Oct 2019, 11:39

i have arrived at similar conclusions. v2 with the all the recent additions(past year) has been a joy to write in, but the hamfisted way of creating/passing/calling functions really hampers an all-out functional style of programming

im not saying this to disparage ur work, just saying it as it is. i dont know what needs to change(delete autoinclude, introduce keywords, operators, w\e) to make this work, but as an end user id be willing to part with some of these feature. not sure if u as a maintainer would be, but i would hope so. cheers
iseahound
Posts: 460
Joined: 13 Aug 2016, 21:04
GitHub: iseahound

Re: Changes to %fn%(), fn.call() or func('fn') syntax?

03 Oct 2019, 23:06

The simple, elegant solution: function objects are functions and objects. Just like in v1 when obj.functor was a function reference to obj.functor(). There just isn't another solution without adding a meta-layer of complexity.
iseahound
Posts: 460
Joined: 13 Aug 2016, 21:04
GitHub: iseahound

Re: Changes to %fn%(), fn.call() or func('fn') syntax?

03 Oct 2019, 23:13

sirksel wrote:
02 Oct 2019, 08:54
[*]When creating derived functions that are partially applied, I get a lot of this in my code: Func("myfunc").Bind(x) or y=>%myfunctor%(x,y) -- or sometimes even y=>myfunc(x,y) and myfunctor.Bind(x), to minimize the Func("") and %% requirements. It would be great to be able to define curriedfunc := curry(myfunc) or curriedfunctor := curry(myfunctor) in a parallel way, and then partially apply to either as curriedfunc(x) or curriedfunctor(x). I use a curry function today, but as noted above, the parallel structure isn't quite there.
Ideally partial application should be implied by sending an insufficient number of arguments for evaluation. This definitely will reduce startup error checking (but Haskell does it and uses lazy eval). It's just super frustrating getting a function reference in the 1st place, and the fact that there isn't one single function for Func() and ObjBindMethod() makes it even more confusing.
User avatar
nnnik
Posts: 4274
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Changes to %fn%(), fn.call() or func('fn') syntax?

04 Oct 2019, 03:55

Ideally partial application should be implied by sending an insufficient number of arguments for evaluation.
Sounds like a complete disaster to me.
Recommends AHK Studio
sirksel
Posts: 53
Joined: 12 Nov 2013, 23:48

Re: Changes to %fn%(), fn.call() or func('fn') syntax?

04 Oct 2019, 06:20

To be clear, I'm not advocating "auto-currying" (or partial application implied by sending an insufficient number of parameters) as part of the language.

I was only suggesting that parallel syntax be implemented between (1) explicitly defined and (2) derived functions (functors) for two things: (a) calling them always as myfunc() and (b) referencing the function object (e.g., for passing as a parameter) always as simply myfunc.

My examples of curry, map, etc. were just examples of aspects of functional programming that would be better enabled by these changes. I'm not suggesting (i) that any of these FP functions be added to the standard library, (ii) that function evaluation must be inherently lazy like Haskell, (iii) that any or all functions should be automatically curried, or (iv) that AHK be represented in any way as an FP language. Indeed, there are two sides to all the usual arguments of FP vs. imperative, where currying is helpful vs. confusing, etc. It seems to me that folks (like me) who have use cases for map, filter, curry, etc. can simply implement them and explicitly call them on functions where appropriate.

I'm only suggesting that AHK might want to allow for a level of agnosticism (parallel syntax) between explicit and derived functions when calling and referencing them -- which then unlocks a lot more possibilities and much clearer and more readable code for those that choose to use AHK for functional programming (or otherwise have need to employ a lot of functors). Sorry if that wasn't clear.
Helgef
Posts: 3987
Joined: 17 Jul 2016, 01:02
Contact:

Re: Changes to %fn%(), fn.call() or func('fn') syntax?

04 Oct 2019, 06:45

I'm only suggesting that AHK might want to allow for a level of agnosticism (parallel syntax) between explicit and derived functions when calling and referencing them -- which then unlocks a lot more possibilities and much clearer and more readable code for those that choose to use AHK for functional programming (or otherwise have need to employ a lot of functors).
Specifically, what is not currently possible? (Apart from calling var() as opposed to %var%()). I think the sequence %%() is ugly, but a separate syntax for calling an explicitly defined function vs calling a functor have positive implications on readability, error detection and performance, as have already been mentioned (somewhere).
in v1 when obj.functor was a function reference to obj.functor()
This conflation was a source of many problems, it would be very unnatural to introduce these problems by conflating syntax for functors and explicit functions now that steps has been taken to remove these problems for objects' data and interface.

Cheers.
sirksel
Posts: 53
Joined: 12 Nov 2013, 23:48

Re: Changes to %fn%(), fn.call() or func('fn') syntax?

04 Oct 2019, 07:46

Understood, Helgef. You're completely right that functional programming is definitely possible with all the great changes made in AHK v2, and I've been maintaining a decent size FP code base in it for a year or so. As you point out, it just isn't too pretty or easy-to-type or easy-to-remember (your own explicit vs. derived functions), especially whenever you have more derived than explicit. But it's definitely possible, so perhaps my word choice above was poor.

It's an interesting point that the momentum of the data/interface changes run counter to this suggestion. I hadn't thought about that. I guess it just seemed to me like derived functions are more of an advanced concept, so those who use them will probably understand concepts like shadowing in the namespace. Maybe the following might be an implementation alternative that keeps the namespaces separate, but instead introduces a couple of new syntax inferences:
  1. For Func("myfunc") references, the Func("") wrapper is implied whenever an explicit myfunc function is defined, but there is no defined in-scope variable named myfunc. When such a variable does exist, the variable takes precedence, and the full Func("myfunc") syntax is required to get the function reference.
  2. As an alternative to calling derived functions (or any callable objects) as %myfunc%(), perhaps the myfunc() syntax could also be used, except in the case where an explicitly defined function of the same name exists. In this case, the defined function takes precedence, and the %myfunc%() syntax is required to call the callable object. I completely understand, as Lexikos as others pointed out earlier, that this would have implications to the robustness of load-time checks. Maybe an optional warning could be generated instead, enabled by default and disabled by #Warn?
I'm sure there are more implications than I'm considering here. Helgef, I know you and Lexikos and others know the code base inside and out, and your calls have been great so far. I'm just freelancing a bit, and probably making assumptions I shouldn't make. To your point, FP is possible, just ugly. If the current state is the way it needs to stay to preserve robustness of error-checking and/or avoid ambiguity for new programmers, that makes sense. I would only say that, aside from error-checking implications, function objects are kind of an advanced topic. Maybe if the implementation always assumes data/built-ins/explicit functions whenever ambiguity arises -- new users might not run afoul of these syntax/inference suggestions as much? Just a thought.

EDIT: Tried to make language more precise to clarify that I'm asking about the way we call function/callable objects more generally, not just user-defined functors.
Last edited by sirksel on 04 Oct 2019, 12:19, edited 3 times in total.
Helgef
Posts: 3987
Joined: 17 Jul 2016, 01:02
Contact:

Re: Changes to %fn%(), fn.call() or func('fn') syntax?

04 Oct 2019, 08:10

Hi @sirksel, thanks for sharing your ideas.

A small correction,
Helgef, I know you and Lexikos and others know the code base inside and out
Cheers.
iseahound
Posts: 460
Joined: 13 Aug 2016, 21:04
GitHub: iseahound

Re: Changes to %fn%(), fn.call() or func('fn') syntax?

04 Oct 2019, 09:55

I just double checked and functors have straight up been deleted from the v2 language. Used to be possible to define a class that extended a functor class, and call the class directly as if it were a function. Just to be clear: functions passed by reference aren't functors. They're just meta objects, second class (because of the special syntax required to invoke them). Which is sad because the fat-arrow syntax is really nice.
Helgef
Posts: 3987
Joined: 17 Jul 2016, 01:02
Contact:

Re: Changes to %fn%(), fn.call() or func('fn') syntax?

04 Oct 2019, 10:32

No, see User-Defined. You can use the static keyword if you like.

Return to “AutoHotkey v2 Development”

Who is online

Users browsing this forum: No registered users and 6 guests