ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

Propose new features and changes
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

16 Nov 2018, 01:55

iseahound and I seem to mostly agree.

Although the notion of a default base object might seem strange to some people, it is not really that deviant.

Most object-oriented programming languages use a single inheritance model where there is one class or object at the root of the type hierarchy. If the programming language is prototype-based, like AutoHotkey, instead of class-based, the root object can be mutated.

People who have a hatred of domain-specific languages are either inexperienced or have only experienced bad examples. Domain-specific languages can work well, better than any alternative, even if they are embedded in another programming language. The best example I know of is Chicken Scheme when using implicit renaming macros.

That said, mutating the root object in a prototype-based programming language seems to be one of the worst ways to implement metaprogramming. It tends to encourage Ruby-like monkey patching rot. Why do I suggest it then? Because it would push AutoHotkey toward a coherent type hierarchy, which might in turn make it possible to recognize the type of values without resorting to memory peeking hacks that break constantly.

Cross-script compatibility is a pipe dream so long as AutoHotkey can be ‘configured’ via global settings that do things like determine whether comparisons are case sensitive. Consider how this interacts with source code that expects a different conglomeration of settings or when one of these settings is toggled in one ‘thread’ (e.g. to perform case-sensitive comparison in one place) to another’s surprise. I personally cope with this by setting everything to what it would be in v2, turning on all debugging support, and leaving everything else at default in the groundless belief that this will minimize the effort in porting my code in the future, will make my code as compatible as possible with others, and will cause me to be less likely to ignore a defect in my code. Programming languages should not have their own mutable global state. Mutating state is like mutating DNA in real life. A little is necessary (e.g. for evolution). Too much gives you cancer.

One reason functions feel so strange in AutoHotkey is function and variable namespaces are separate.

The only other programming language that made this decision that I know of is Common Lisp. I am aware of the arguments for it (proponents claim it makes Common Lisp’s unhygenic macro system less unsafe) and why those arguments are weak (most accidental capture is caused by variable names colliding with variable names, not variable names colliding with function names) but not entirely without merit (it does let you name a variable list without losing access to the function named list in the same scope). (function foo) (or the shorthand #’foo) and (funcall foo) in Common Lisp is equivalent to Func(“Foo”) and Foo.Call() (or the alternative %Foo%()), respectively, in AutoHotkey.

In most widely used programming languages, like C, the procedure name is a variable containing a pointer or reference to the procedure.

I can live with separate function and variable namespaces in AutoHotkey. What I am having a great deal of trouble living with is, as iseahound said, “function objects are not function objects”. When one receives a function object, one never knows what one can do with it, except that it can be called. That is inadequate. It does not allow one to reliably use Bind(Args*). It does not allow one to type check it.

As for error handling, I believe there are two good designs.

One is a condition system like Common Lisp's. When an error occurs in a condition system a handled error can be automatically corrected by calling a restart (a built-in or user-defined function that corrects the state) or unwind the stack like typical exception handling but an unhandled error allows you to examine and change the state (e.g. the local variables) manually and then continue.

The other is only usable in statically type checked languages like Haskell. The solution consists of two concepts, sum types and option types. Functions that can experience failure return a sum type, which can either be a useful value or a data structure describing the error and its causes. Variables that can contain null (nothing) are option types. Only variables declared to be option types can contain null. Code using sum types or option types must handle all cases, enforced by the static type checker.

I can live with AutoHotkey’s exception handling. It is not as nice as either option I mentioned, but it is tolerable. Any acceptable error handling mechanism must require no effort to detect errors. We know from experience that programmers do not reliably write code to detect errors, so this is a matter of safety, not convenience, though it is also more convenient. All errors must be reported via the same mechanism. AutoHotkey’s random selection of returning an empty string, setting ErrorLevel, setting A_LastError, or throwing an exception is unacceptable. All but the last require effectively writing error checking code every other line. Dealing with so many competing error handling mechanisms is intolerable. Other than AutoHotkey not using exception handling for everything, the biggest problem with it is it is based on the idea of throwing an Exception data structure containing strings (though people are often quick to remind you that you can, uselessly, throw anything). Acceptable exception handling is based on the idea of having a type hierarchy where similar errors are grouped under the same superclass and the class gives an indication of the cause of the error (though exceptions can and should also carry a custom, more detailed, message). This allows error handling code to selectively catch certain types of errors and handle similar errors the same way. Python’s exception handling is nothing special, but it could be used as inspiration for improving AutoHotkey’s exception handling in the ways I just mentioned. I find Python’s exception handling to be adequate.

The problem with AutoHotkey is it creates a very unsafe programming environment (e.g. by having randomly designed syntax (% must be used in the right places, but there is no pattern to where expressions are implicit or explicit), ignoring errors, and having few if any common interfaces) and then it does not provide any coping mechanism (e.g. if you could at least check if something you want to do would not work, you can report an error or do something else that will work). I want to at least be able to recognize the type of all values so that I can cope with the rest of the language’s design, but what I really want is AutoHotkey to start being consistent and stop conflating concepts (like arrays and dictionaries) so that all these problems would be eliminated.
Last edited by [Shambles] on 16 Nov 2018, 06:00, edited 1 time in total.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

16 Nov 2018, 05:39

I never said that I do not see the same problems - in fact I have repeated this argument over and over again.
However there is no hope for v1.

In order to check the amount of parameters on any method that any AHK Object provides we may have to remove meta-functions.
Recommends AHK Studio
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

16 Nov 2018, 05:44

And like I said the majority of what you call function objects only implement the callable interface and are not functions.
In v2 we want to move all error handling to throwing exceptions.
Recommends AHK Studio
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

16 Nov 2018, 06:13

nnnik wrote:
16 Nov 2018, 05:39
I never said that I do not see the same problems - in fact I have repeated this argument over and over again.
However there is no hope for v1.

In order to check the amount of parameters on any method that any AHK Object provides we may have to remove meta-functions.
I can understand how meta-functions could cause problems determining whether a property exists (because they can potentially create an infinite number of 'fake' properties), but I cannot imagine how they would interfere with determining the number of parameters of a function object. __Call(Name, Args*) should be a user-defined function object and thus has the potential to contain all the necessary information. The problem is some function objects choose to not preserve necessary information, even though AutoHotkey could be changed to preserve that information, and these changes should not break backwards compatibility.

I have used meta-functions to do useful things before. In Plaster I used them to report errors when Object and Array keys that did not exist were accessed, to reduce the frustration that comes from silent failure. In the libraries I am currently working on, I use them to redirect attempts to read properties I did not explicitly override to the wrapped object. Specifically, I use it to make arbitrary objects act like function objects. For example, I can turn an Object containing the key "foo" associated with the value "bar" into a function object that will return "bar" when passed "foo" as its argument. This is more useful than it might appear. All data structures are callable like functions in Clojure where they are frequently used to build arguments for function applications (variadic calls in AutoHotkey speak).
nnnik wrote:
16 Nov 2018, 05:44
And like I said the majority of what you call function objects only implement the callable interface and are not functions.
In v2 we want to move all error handling to throwing exceptions.
Moving all error handling to throwing exceptions would be the biggest positive step AutoHotkey could take. I hope the design of the exception handling will also be corrected to make selective catching and catching multiple related errors by using a common superclass possible.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

16 Nov 2018, 06:45

You are oversimplifying things:
How many parameters would the following objects have at each point in time?

Code: Select all

Msgbox using `%fn`%()
;inconsistency
t := new test()
%t%("Hello World")
%t%("Hello World",  "Hello World 2")
%t%()

Msgbox using fn.call
;featuring the stuff of nightmares
t2 := new test()
t2.call("Hello World")
t2.call("Hello World", "Hello World 2")
t2.call()

class test {
	
	static call := func("test.fn1")
	static __call := func("test.meta1")
	
	meta1(b, c,  d) {
		Msgbox switch mode 1 to mode 2
		this.base.call := this.fn2
		this.base.__call := this.meta2
	}
	
	meta2(p*) {
		if (p.length()<=2) {
			Msgbox switch mode 2 to mode 1
			this.base.call := this.fn1
			this.base.__call := this.meta1
		}
	}
	
	fn1(text:="Hello World") {
		Msgbox % text
	}
	
	fn2(text,  text2 := "Also hello world") {
		Msgbox % text . " `n" . text2
	} 
}
Recommends AHK Studio
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

16 Nov 2018, 07:28

nnnik wrote:
16 Nov 2018, 06:45
You are oversimplifying things:
How many parameters would the following objects have at each point in time?

Code: Select all

Msgbox using `%fn`%()
;inconsistency
t := new test()
%t%("Hello World")
%t%("Hello World",  "Hello World 2")
%t%()

Msgbox using fn.call
;featuring the stuff of nightmares
t2 := new test()
t2.call("Hello World")
t2.call("Hello World", "Hello World 2")
t2.call()

class test {
	
	static call := func("test.fn1")
	static __call := func("test.meta1")
	
	meta1(b, c,  d) {
		Msgbox switch mode 1 to mode 2
		this.base.call := this.fn2
		this.base.__call := this.meta2
	}
	
	meta2(p*) {
		if (p.length()<=2) {
			Msgbox switch mode 2 to mode 1
			this.base.call := this.fn1
			this.base.__call := this.meta1
		}
	}
	
	fn1(text:="Hello World") {
		Msgbox % text
	}
	
	fn2(text,  text2 := "Also hello world") {
		Msgbox % text . " `n" . text2
	} 
}
The number of parameters would depend on which function object was assigned to Call and __Call at the moment. The information on a function object is associated with the function object, not the class or object (dictionary) it is stored in (this is not a statically type checked programming language).

You do not need meta-functions to create this sort of confusion. Any code can swap a method on a user-defined type by simply reassigning what is associated with the respective property (i.e. key).

Code: Select all

; Look Ma!  No meta-functions!

class Fooer
{
    Foo()
    {
        ; I should have 1 parameter, the implicit "this".
        MsgBox % "foo"
    }
}

X := new Fooer()

X.Foo()  ; Speak Ubu!
MsgBox % "# of parameters: " . X.Foo.MaxParams  ; Check it out!  I support all the function object interface.  Only BoundFunc instances are broken!

IckyFoo(this, X, Y)
{
    ; I should have 3 parameters.
    MsgBox % "bar"
}

X["Foo"] := Func("IckyFoo")  ; I pity the Foo!  Clobber it!
; I could have also done this:
;X.Foo := Func("IckyFoo")

X.Foo("Junk", "Placeholder")  ; Speak Ubu!
; I could have also done this:
;X["Foo"]("Junk", "Placeholder")
MsgBox % "# of parameters: " . X.Foo.MaxParams
; I could have also done this:
;MsgBox % "# of parameters: " . X["Foo"].MaxParams
If you did this in a program you cared about, you would usually be writing bad code, but this is possible in almost every dynamically type checked, highly reflective programming language. You could do the same thing in Smalltalk or Python, though the average programmer in those communities would be upset with you. You could also do it in Ruby, where it is a common practice in the community.

Further, since AutoHotkey is prototype-based, you do not have to limit yourself to just modifying instances of a class. You can modify the original class itself. It is all just objects. Again, this has nothing to do with meta-functions and everything to do with AutoHotkey being prototype-based and reflective.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

16 Nov 2018, 08:08

My case is fundamentally different from your and I do have to assume that you did not run the code.
In the first case only the meta functions will be called and not the methods behind that - in the case of useing %fn%() the parameter count is therefore equivalent to 0-1 or 1-2 depending on the mode.
When using the .call() method the parameter count is equivalent to 0-2 since .__call will switch out to the correct mode before calling the method.
Recommends AHK Studio
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

16 Nov 2018, 08:34

nnnik wrote:
16 Nov 2018, 08:08
My case is fundamentally different from your and I do have to assume that you did not run the code.
In the first case only the meta functions will be called and not the methods behind that - in the case of useing %fn%() the parameter count is therefore equivalent to 0-1 or 1-2 depending on the mode.
When using the .call() method the parameter count is equivalent to 0-2 since .__call will switch out to the correct mode before calling the method.
You are correct that I did not run it, but I understand the idea. I do not believe anything I said is incorrect, nor do I believe your case is fundamentally different.

Also, __Call(Method, Args*) was slated for removal in v2, last I heard. Though I am no longer clear on whether you are trying to object to fixing what is wrong with Bind(Args*) and BoundFunc instances in v1 or v2. I am 100% positive it is possible to fix. Whether the developers will care about opinions other than their own, I am less certain. I complain because if nobody does, then it is extremely unlikely to get fixed, and I care because I actually use AutoHotkey and would prefer the experience be less unpleasant.

If a function object preserves its number of parameters, and all of the built-in ones do except instances of BoundFunc, you can always query them. The members are attached to the function objects themselves (and user-defined methods are just normal function objects), so meta-functions are irrelevant. Meta-functions are, themselves, just function objects, so if they are not BoundFunc instances, they can be queried the same way.

Any shenanigans that make it harder to tell which function object is in a location at a time only says something about writing bad code, not function objects or meta-functions. Although I have encountered many programming languages that make writing good code difficult, I have never encountered one where writing bad code is difficult.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

16 Nov 2018, 09:29

Do you have any source on how Powershell gets the amount of parameters for any COMObject?
Recommends AHK Studio
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

16 Nov 2018, 10:31

nnnik wrote:
16 Nov 2018, 09:29
Do you have any source on how Powershell gets the amount of parameters for any COMObject?
I do not. I tried to figure that out before PowerShell was open sourced. I was trying to use DLL calls to do the same thing from AutoHotkey. I used Microsoft's documentation to try to find the right functions or methods to call. I do not remember much about them any more, but recall that I was getting sensible results for some COM objects but nonsense for others. PowerShell was working for all of them.

Get-Member is the command used to interrogate COM objects in PowerShell. This is a working example: New-Object -ComObject Scripting.Dictionary | Get-Member

The answer is somewhere in the source code here: https://github.com/PowerShell/PowerShell

This might be the place to start: https://github.com/PowerShell/PowerShel ... tMember.cs

As far as I know this has nothing to do with function objects because I have never seen a loose function exported as a COM object and as far as I know you cannot make BoundFunc instances from COM object methods. But if you have other reasons to care, that is what appears to be the official PowerShell repository.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

16 Nov 2018, 11:14

Thanks for the links :)

You can use ObjectBindMethod on COM Objects.
Recommends AHK Studio
iseahound
Posts: 1444
Joined: 13 Aug 2016, 21:04
Contact:

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

16 Nov 2018, 11:21

Actually I never really noticed the discrepancy between a function namespace and a variable namespace. In theory, a lot of the problems I mentioned could be solved by merging the two spaces.

Code: Select all

"".base.length := Func("StrLen")
; would become
; "".base.length := StrLen() ; or even StrLen
MsgBox % "hi every1 im new!!!!!!! *holds up spork*".length()
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

16 Nov 2018, 11:29

I dont have any particulary strong feelings about this. But the main variables that store the functions should be "extra super global"(because you can and should deactivate the global and super global scop with local but still want to access functions) and read-only.
Recommends AHK Studio
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

16 Nov 2018, 12:01

I do not believe many problems would be solved by merging the function and variable namespaces, but I would not be very offended by it either. I have gotten in the habit of using the same name for a lot of my parameters as AutoHotkey's constructors (e.g. Array, Func, etc.). I would have to change that. On the other hand, I use function objects heavily, and this change would eliminate the extra syntax to retrieve and call function objects. These trade-offs are familiar to anyone with some experience with Common Lisp and Scheme. It would do nothing to eliminate AutoHotkey's inconsistency and conflation though.

AutoHotkey has too many nonsensical 'modes' for variable access. There is only one behavior that is sensible if you have experience in other programming languages. 'force local mode' is the closest equivalent to this behavior that AutoHotkey currently offers. I would rather they fix AutoHotkey's scope handling and ditch all these 'modes' than add super turbo championship edition globals and make me stick more boilerplate on the beginning of every function to shut off bad behavior. If you perform variable lookup for reads and writes from the most local to the most global (i.e. normal lexical lookup) most behavior will be sane, especially if you write good code without using a lot of mutable global variables.

To avoid accidentally clobbering a variable outside your scope, without having to explicitly import everything you use in every function, you need definition-mutation separation. That is, you need one construct that constructs and initializes a variable and another that mutates a variable. For example, def x 0 could create a variable named x with the value of 0 while x := 1 might mutate an existing variable named x by setting it to 1. This makes it clear whether you intend to create a local variable that happens to have the same name as a global one or whether you intend to change the value of the global one. It has the added benefit of reliably detecting typos in variable names without requiring static type checking. Oh, and if you ever hope to have anonymous functions that work reliably and do not require you to specify everything they should be able to refer to outside their local scope, you will have to do this anyway. Parameters should always be local.

I know of no other programming language has this sort of scope problem. I do know of several that made the dynamic scope mistake, which, amazingly, AutoHotkey avoided.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

16 Nov 2018, 12:36

One AutoHotkey function, IsObject(Value), says that function objects are objects and another, ObjGetBase(Object), says that they are not (unless they are user-defined).
Function objects are objects, the second function tells you it is the wrong type of object. There is no contradiction.
That does not make AutoHotkey having these two incompatible notions a desirable thing.
I answered your bug report, I neither agreed nor disagreed with any of your opinions.

Cheers.
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

16 Nov 2018, 12:38

iseahound wrote:
16 Nov 2018, 11:21

Code: Select all

"".base.length := Func("StrLen")
; would become
; "".base.length := StrLen() ; or even StrLen
MsgBox % "hi every1 im new!!!!!!! *holds up spork*".length()
It would become "".base.Length := StrLen, yes. AutoHotkey user-defined functions and methods are both non-BoundFunc function objects, but when called as a method they expect an extra parameter for the implicit "this". The "this" in this case would be the string.

That functions and methods are the same thing, just with an implicit "this" parameter when called a certain way, is one of the few aspects of AutoHotkey's design that I find elegant. Python works the same way, if memory serves.

In most programming languages the procedure name is just a variable with a pointer or reference to the code of the procedure. The term "Lisp-2" refers to this, even outside Lisp systems.
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

16 Nov 2018, 13:04

nnnik wrote:
16 Nov 2018, 11:14
Thanks for the links :)

You can use ObjectBindMethod on COM Objects.
I hope they help.

It is good, and surprising, to know that ObjBindMethod(Obj, Method, Args*) works on external COM objects. Thank you. Someday I may need to use it that way.

If the resulting BoundFunc objects could not preserve the necessary information for external COM objects, it would still be preferable if they did for built-in and user-defined function objects, where it should be very much possible. There is also absolutely no reason a Bind(Args*) method should not be available on every BoundFunc object. It does not require interrogating the object. It just requires the willingness to provide the method and the ability to store the arguments already provided. I would think of it like division. Sure, you cannot divide by 0, but it is nice to be able to do it to every other number. Of course, if you can make it work even for external COM objects, that's even better. The more consistent AutoHotkey is, the happier I am!
iseahound
Posts: 1444
Joined: 13 Aug 2016, 21:04
Contact:

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

16 Nov 2018, 14:31

I thought about merging the function and variable namespaces some more, and decided it's too impractical. If anything, calling "".base.length := StrLen should look for a variable named StrLen first before failing and looking in the function namespace for StrLen(). I'm not sure how AHK handles command syntax but the same problem arises when the first word of a line is StrLen and there is an object also named StrLen
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

16 Nov 2018, 23:07

iseahound wrote:
16 Nov 2018, 14:31
I thought about merging the function and variable namespaces some more, and decided it's too impractical. If anything, calling "".base.length := StrLen should look for a variable named StrLen first before failing and looking in the function namespace for StrLen(). I'm not sure how AHK handles command syntax but the same problem arises when the first word of a line is StrLen and there is an object also named StrLen
Classes just create objects that are stored in variables in the normal variable namespace. You are forced to become aware of this when using 'force local mode' because you will have to include global ClassIUseHere in your procedures to make your code work. So nothing confusing happens. If there were a single namespace and there was a variable named StrLen that contains a function (like the usual StrLen(Str) function) or anything else, that is what would get used when using 'command syntax'.

As for command syntax as a whole, it is a design flaw copied from Microsoft Script-It. The authors of Script-It made the mistake because they believed Windows users would be familiar with using the command line, so it would be easier to use if everything looked like launching programs from the command line. This belief might have even been true before about the mid 1990s. It is most assuredly not true today.

Most imperative programming languages are constructed from "statements" and "expressions". AutoHotkey calls the former "commands", for some reason. Statements are normally used for control flow, like if, while, and return. Expressions are used for everything else. Statements do not return values. Some people find it difficult to imagine what things like if and while should return. Those same people tend to eventually invent the ternary operator if test_expression ? true_expression : false_expression because they find themselves writing code that does this repeatedly. There are languages where the equivalent to if and while return values, like Lisp, which was first implemented in 1961. Everything is an expression in these languages, making uninitialized variables impossible. if behaves exactly like the ternary operator, and the while equivalent is tail recursion, which ultimately returns the last return value of the last line at the end of the loop. A procedure's return value in these languages is just the return value of the last line of the procedure, enforcing the good practice of single entry, single exit.

Expressions are better than statements because being able to return a value is better than not being able to. For this reason, even programming languages that use statements (which is most of them) allow expressions almost everywhere.

Command syntax is a mistake because it does not make things easier, because the average person is not more familiar with the command line than anything else (e.g. high school algebra) and command syntax does not compose. It leads to ugly hacks like having to create "out variables" for the commands to return values through because they cannot be nested.

Composition is what makes programming comprehensible for humans (the computer does not care). It lets you make big complicated things by sticking small simple things together like Legos. Programming languages have been evolving away from concepts that do not compose. Some will always remain. I/O is fundamentally side-effecting, and thus does not compose. At least one global mutable variable (and global variable mutation does not compose) will have to be used in any program that handles events (like key presses and mouse motions) so that each event does not start the program anew. Anyone that tries to tell you otherwise (e.g. proponents of Haskell's 'pure' monadic I/O) is trying to sell you snake oil (Haskell is really impure, but it forces you to keep the impurity out of most of your code (a legitimate good thing) by making most of its built-in constructs refuse to work with impure constructs).

AutoHotkey should abandon command syntax for everything except control flow so that it becomes both more powerful and more familiar (to anyone that has been exposed to high school algebra or another programming language) and it should allow expressions everywhere that they could be useful so that the language becomes more powerful and consistent. This has been suggested to the development team, repeatedly. They are attached to the 'quirks' of AutoHotkey and claim that it makes it easy to use because programmers who have Stockholm syndrome from having learned AutoHotkey and not having learned any other programming language claim it is 'easy'. There is nothing 'easy' about a programming language where expressions are only allowed in random places, but you can use pairs of %s (which do not themselves compose because they are non-directional, leading to hacks like adding parentheses around them) to force an expression to be evaluated, but if you use them where they are not necessary they will try to perform a dereference, which might silently fail or 'work' but do something unintended.

At least in v2 you can ignore command syntax. In v1 the best coping mechanism I know of is wrapping non-control-flow commands in functions. As far as I know, religiously rereading the manual is the only way to ward off % demons, even in v2.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: ObjGetBase(Object) and ObjSetBase(Object, BaseObject) Need to Change

17 Nov 2018, 03:27

Command Syntax has been removed in v2.
Recommends AHK Studio

Return to “Wish List”

Who is online

Users browsing this forum: No registered users and 38 guests