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

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

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

14 Nov 2018, 20:57

The Short Version:

ObjGetBase(Object) and ObjSetBase(Object, BaseObject) used to return an empty string when they failed.

The Long Version:

Code: Select all

class AClass
{
    Hello()
    {
        MsgBox % "Hello World!"
    }
}

"".base.base := AClass

"".Hello()

ObjGetBase("")
The code above successfully sets the base object of the default base object and calls a method on it, but ObjGetBase(Object) fails to get the default base object. Specifically, it throws an exception because an empty string is not an object.

The expected behavior is it would return the default base object.

ObjSetBase(Object, BaseObject) has the equivalent problem. It throws an exception if it deems its first argument to not be an object. You could claim this is the expected behavior since the documentation for Default Base Object says that it cannot be set like "".base := Object(), but that is just another inconsistency that should be eliminated.

This problem runs deeper than it might appear. This is not the first time I have complained about it (see https://autohotkey.com/boards/viewtopic.php?t=6969 )

AutoHotkey's type system is fundamentally broken. It has two incompatible notions of the "Object" type. One notion is "a value that has properties or methods and has no string representation". The other notion is "a dictionary type that has unreliable indexing, conflates its interface with its contents, and serves as the basis for sparse Arrays and user-defined types".

Code: Select all

Hello()
{
    MsgBox % "Hello World!"
}

MsgBox % IsObject(Func("Hello"))

ObjGetBase(Func("Hello"))
The code above confirms that the function object Func("Hello") is indeed an object, but ObjGetBase(Object) throws an exception because the function object Func("Hello") is not an object.

This is not just an academic concern. I am not a fan of silent failure, but I have written code that depended on ObjGetBase(Object) reliably crawling the type hierarchy. An empty string would normally mean there are no more base objects. The empty string is the closest thing AutoHotkey has to null. I used this to detect the type of an object.

My affected code reports an error if the object is of the wrong type (important to combat the pervasive use of silent failure in AutoHotkey) and to avoid unnecessarily wrapping objects. That second chunk of demonstration code is related to the code I use to wrap AutoHotkey's native function objects. The function objects returned by Bind(Args*) and ObjBindMethod(Obj, Method, Args*) do not have a Bind(Args*) method. That means code that needs to use a Bind(Args*) method has to know whether or not the object has that method, and there is no way to detect that for built-in types because they do not support HasKey(Key).

I can work around this by writing functions that behave the way ObjGetBase(Object) and ObjSetBase(Object, BaseObject) used to, but AutoHotkey would be much better if the developers stopped causing more inconsistent behavior and regressions. It creates unnecessary burden on the users writing code to abstract over the inconsistencies. They have to write more code, and the code they already wrote breaks.
Last edited by [Shambles] on 15 Nov 2018, 06:34, edited 1 time in total.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Regression In ObjGetBase(Object) and ObjSetBase(Object, BaseObject)

15 Nov 2018, 00:41

ObjGetBase should not be used for type detection. In AHK v1 there is no method for type detection.
You can use a workaround which reads an entry in the data structure of any object to identify the type of an object.
However that relies on undocumented features. Anyways there is no chance to use ObjGetBase for type detection.
Recommends AHK Studio
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Regression In ObjGetBase(Object) and ObjSetBase(Object, BaseObject)

15 Nov 2018, 04:08

ObjGetBase(Object) and ObjSetBase(Object, BaseObject) used to return an empty string when they failed.
When?
ObjGetBase wrote:An exception is thrown if Object is of an incorrect type.
src: ObjGetBase
It is clearly documented behaviour.
The code above confirms that the function object Func("Hello") is indeed an object, but ObjGetBase(Object) throws an exception because the function object Func("Hello") is not an object.
No it throws an exception because the first parameter is invalid, in this case because the object passed is of incorrect type. It should be clear that Func is of incorrect type from,
Object wrote: AutoHotkey's basic object datatype is an associative array with features which allow its behaviour to be customized. By default, all objects created by {}, [], Object() and Array() support the following:
[...]
Functions:
  • [...]
  • ObjGetBase
  • ObjSetBase
src: Object

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

Re: Regression In ObjGetBase(Object) and ObjSetBase(Object, BaseObject)

15 Nov 2018, 04:09

nnnik wrote:
15 Nov 2018, 00:41
ObjGetBase should not be used for type detection. In AHK v1 there is no method for type detection.
You can use a workaround which reads an entry in the data structure of any object to identify the type of an object.
However that relies on undocumented features. Anyways there is no chance to use ObjGetBase for type detection.
You should not tell someone that they should not do something that they need to do. They will do it anyway if it is possible and practical. This is not about polymorphism vs branches. That is a separate debate, and defending the polymorphism stance requires having a sane (Liskov conformant) type hierarchy, which AutoHotkey does not have. This is about knowing whether a type can be made to work with an operation at all, and how. Knowing that is vital because just trying an operation is not practical when it is impossible to tell the difference between success and failure (an empty string or 0 is a perfectly reasonable successful result in many cases).

Reading the "entry in the data structure", which I will assume is the __Class property (which is documented and is only present in user-defined types), will only tell you the class 'one step up' in the type hierarchy. It will not handle answering the question of whether Foo is of type X when Foo's class Z is being derived from class Y which is being derived from class X. There is an example of this in the v2 documentation for the is operator.

Perhaps you meant hacks involving reading raw memory addresses and knowing the layout of the C++ objects. I will not use those kinds of hacks having already had two libraries that depended on them destroyed by needless inconsistency. Also, they are not necessary for this. ObjGetBase(Object) is sufficient.

There is definitely a chance to use ObjGetBase(Object) for type detection. Not only did I have working code for it before, but I have already rewritten it so that it works like it did before. The mechanism is not hard to understand if you understand recursion. Each call to ObjGetBase(Object) using the previous result takes one step up in the type hierarchy. Then it is just a matter of testing whether that is equal to the value of the variable containing the class (i.e. the class name).

The relevant code for proof:

Code: Select all

Result := false
try
{
    CurrentObject := ObjGetBase(Value)
}
catch
{
    CurrentObject := ""
}
while (not Result and CurrentObject <> "")
{
    try
    {
        Result        := CurrentObject == Type
        CurrentObject := ObjGetBase(CurrentObject)
    }
    catch
    {
        CurrentObject := ""
    }
}
My issue was this behavior changed and broke my code. The change was annoying. Nobody likes having to rewrite code for no reason. I could have tolerated it if the new behavior was better than before, but it is not. If it is to be changed, it should never throw, it should return the default base object when the value has no other base object, and it should return the empty string (the null equivalent) for the default base object's base object.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Regression In ObjGetBase(Object) and ObjSetBase(Object, BaseObject)

15 Nov 2018, 04:18

This is about knowing whether a type can be made to work with an operation at all, and how.
v1,

Code: Select all

can_set_base(value){
	return objgetcapacity(value) != ""
}
:cry:

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

Re: Regression In ObjGetBase(Object) and ObjSetBase(Object, BaseObject)

15 Nov 2018, 04:21

Helgef wrote:
15 Nov 2018, 04:08
ObjGetBase(Object) and ObjSetBase(Object, BaseObject) used to return an empty string when they failed.
When?
ObjGetBase wrote:An exception is thrown if Object is of an incorrect type.
src: ObjGetBase
It is clearly documented behaviour.
The code above confirms that the function object Func("Hello") is indeed an object, but ObjGetBase(Object) throws an exception because the function object Func("Hello") is not an object.
No it throws an exception because the first parameter is invalid, in this case because the object passed is of incorrect type. It should be clear that Func is of incorrect type from,
Object wrote: AutoHotkey's basic object datatype is an associative array with features which allow its behaviour to be customized. By default, all objects created by {}, [], Object() and Array() support the following:
[...]
Functions:
  • [...]
  • ObjGetBase
  • ObjSetBase
src: Object

Cheers.
It changed in either 1.1.29.01 or 1.1.30.00. I do not believe I have used any beta versions, I know that at one point my code worked, ObjGetBase(Object) was introduced in 1.1.29.00 so it could not have been before that, and I have not yet upgraded to 1.1.30.01.

Indeed, the undesirable behavior is documented. I never said it was not.

If you pay close attention you can see that the second code block in my original posting shows that AutoHotkey deems a function object an object in one situation and not in another. I am well aware of the two incompatible notions of object. I mention them in paragraph in the original post.

"It is broken." is not an argument for not fixing something nor is "It is broken, but we documented that".
Last edited by [Shambles] on 15 Nov 2018, 04:27, edited 1 time in total.
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Regression In ObjGetBase(Object) and ObjSetBase(Object, BaseObject)

15 Nov 2018, 04:22

Helgef wrote:
15 Nov 2018, 04:18
This is about knowing whether a type can be made to work with an operation at all, and how.
v1,

Code: Select all

can_set_base(value){
	return objgetcapacity(value) != ""
}
:cry:

Cheers.
That is not what my code does or needs to do.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Regression In ObjGetBase(Object) and ObjSetBase(Object, BaseObject)

15 Nov 2018, 04:36

I myself know of this problem and have argumented against it for quite a while. But like I said there is no method for doing what you need to do.
Even if you need to do it - whats impossible is impossible.
AHK is not a language suited for development at all. v2 fixes this by adding a type function.
It is possible to differ objects by using the internal structure and this is your best bet.
many built in objects simply do not have a base object - they have a method that handles all their calls.

ObjGetBase is used for traversing the structure of Objects created by Object but cannot be used to traverse any other type of object - e.g. a COMObject.
It should not be used to do this either as it is limited towards AutoHotkeys own logic of objects and cannot fit external objects.
Recommends AHK Studio
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Regression In ObjGetBase(Object) and ObjSetBase(Object, BaseObject)

15 Nov 2018, 04:40

Indeed, the undesirable behavior is documented. I never said it was not.
You posted in bug reports, so you suggest there is a problem (as in not working) with documented behaviour. There clearly isn't, you need to post in the wish list or ask for help.
If you pay close attention you can see that the second code block in my original posting shows that AutoHotkey deems a function object an object in one situation and not in another.
If you pay any attention at all, you'd notice that ObjSetGetBase isn't documented for Func objects. You could tell from the documentation and from me telling you, now twice.

Good luck.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Regression In ObjGetBase(Object) and ObjSetBase(Object, BaseObject)

15 Nov 2018, 04:41

As this is not unwanted behavior I moved this to wishlist.
Recommends AHK Studio
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Regression In ObjGetBase(Object) and ObjSetBase(Object, BaseObject)

15 Nov 2018, 05:51

nnnik wrote:
15 Nov 2018, 04:36
I myself know of this problem and have argumented against it for quite a while. But like I said there is no method for doing what you need to do.
Even if you need to do it - whats impossible is impossible.
AHK is not a language suited for development at all. v2 fixes this by adding a type function.
It is possible to differ objects by using the internal structure and this is your best bet.
many built in objects simply do not have a base object - they have a method that handles all their calls.

ObjGetBase is used for traversing the structure of Objects created by Object but cannot be used to traverse any other type of object - e.g. a COMObject.
It should not be used to do this either as it is limited towards AutoHotkeys own logic of objects and cannot fit external objects.
Not only is what I need to do possible, but I have done it, and redone it, and even posted the relevant code that does it above. I do not understand this line of argument.

What my code does is, as far as I can tell, exactly the same as what is does in v2 when testing user-defined types.

The remaining problem for me is if I ever need to write code to do this again, I will have to write boilerplate to work around behavior that is never desirable. I explained how both functions should be changed already.

As for whether AutoHotkey is a language suited for development, I could argue it either way. Its syntax is random and dangerous. One never knows where to put a % without looking up the particular situation in the manual. Almost anything will parse, but it will often not do what you expect. Its semantics seem to come from the bad parts of JavaScript and PHP. It ignores almost all the lessons learned since the 1970s about safe and easy programming language design. On the other hand, all the necessities are provided. Unlike AutoIt, it does have the ability to use references to build data structures (though you can do this with more suffering in AutoIt using Scriping.Dictionary COM objects). The I/O facilities are not perfect (e.g. the lack of a grid layout manager makes creating scalable GUIs especially unpleasant), but they are the best available for controlling the GUIs of other programs. Many programmers deemed Perl, JavaScript, and PHP suitable for development, possibly in bad taste.

As for why I write 'complicated things' in it, it is because marshaling data between better designed programming languages and AutoHotkey is often labor intensive or impossible (calling AutoHotkey is often possible; calling back from it, not so much) and it is possible to abstract over the warts. I just wish warts would quit being added.

Sadly, there is nothing else that is practical for remapping keys in software that does not support it, adding rapid fire in games that do not support it, automating the installation of Windows software, or automating the reconfiguration of Windows software. I blame those last two on Windows programmers never realizing businesses and schools exist. They seem to think that the person that installs or reconfigures software is at each machine to walk it through a dozen steps using the GUI for every task. AutoHotkey makes it possible to bodge the mess Windows programmers created by using Active Directory or other administrative software (e.g. Symantec Ghost) to transmit and execute AutoHotkey programs en masse.

As for COM objects, they do not seem to have a notion of a superclass. I also usually use and discard them as soon as possible because they work so poorly with the rest of AutoHotkey (e.g. try iterating over a COM SafeArray).

My current use cases for testing the class of a value are:
  • reporting type errors so that debugging does not drive me more insane because the language mostly ignores them
  • determining if a type has already been wrapped so that I can force consistent behavior because the language is terribly inconsistent
For example, I wrote a class that ensures that calling Bind(Args*) always returns a function object with a Bind(Args*) method. The programming language should do this, but I have no control over that. I use the ObjGetBase(Object) trick to avoid wrapping function objects more than once.

I use the ObjGetBase(Object) trick to determine if properties exist, though that only works for user-defined types, so that I can force consistent behavior because the language is very inconsistent.

For example, if Object (in the broken dictionary sense, not the any object with members sense) used Get(Key) and Set(Key, Value) methods, it could avoid conflating its interface with its contents. Then it would be possible to store any string key in an object without worrying about breaking methods on the object. I cannot detect if a property contains a function object because it is not possible to determine the type of function objects (the only thing you can depend on the existence of is the Call(Args*) method) without memory hacks (and I already wrote a library that did that and was broken when BoundFunc objects had an interface incompatible with the preexisting function objects), but I can determine if a property named "Set" or "Get" exists on a user-defined type and assume that is a method. This has allowed me to write code that performs the same operation on types that do not share a common superclass. The code written on top of such ugly hacks can be elegant.
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Regression In ObjGetBase(Object) and ObjSetBase(Object, BaseObject)

15 Nov 2018, 06:05

Helgef wrote:
15 Nov 2018, 05:06
I downloaded 1.1.29.00, it throws too.
I have not tried previous versions with my old code and today's input, but I do know that my code worked until today. It is possible that something is different about the input I used today. The code that threw today detects the type of a function object to ensure that it is not wrapped more than once in a class that makes Bind(Args*) return function objects with a Bind(Args*) method. The only way this could have happened without a regression is if it happened to never process a built-in (as opposed to user-defined) function object.

If this was not a regression, I own up to the mistake, and I am sorry for the false accusation. This is not about my ego. This is about the high level of frustration I experience when dealing with this programming language. I want it to get better for everyone. I have aired my complaints and released libraries to try to make that happen.

If the current behavior is as it always has been, it should still be changed in the ways I described. We should not have to care whether a function object is built-in or user-defined. They should all have the same basic interface and work with the same code.
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

Re: Regression In ObjGetBase(Object) and ObjSetBase(Object, BaseObject)

15 Nov 2018, 06:33

Helgef wrote:
15 Nov 2018, 04:40
If you pay any attention at all, you'd notice that ObjSetGetBase isn't documented for Func objects. You could tell from the documentation and from me telling you, now twice.

Good luck.
I am very much paying attention. 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). I have already told you, now twice, that I know that AutoHotkey has two incompatible notions of object-hood. That does not make AutoHotkey having these two incompatible notions a desirable thing.

To put it into terms you might understand...

Imagine you have to cut up a fallen tree so that it can be hauled away. You are presented with two tools. One is a spoon made out of fresh Playdough. The other is a rusty chainsaw with a blade at both ends (one where the handle should be) and a biohazard sign on the blades warning about tetanus covering the surface.

That tree represents a task like automating the installation of a SMART Board driver. The spoon made of Playdough represents most other programming languages. The rusty, tetanus covered, double-ended chainsaw represents AutoHotkey. Obviously, the only tool that will do the job is AutoHotkey, but what you really want is a safe, single-ended chainsaw.

I do jobs that fallen tree represents regularly. Figuratively speaking, I can handle that chainsaw with some tongs and try to be very careful, but it is getting hard to live with the wounds and doctor bills.

My luck is as good as you could expect in this situation. The people that can help seem to not care. Figuratively speaking, I have already fashioned myself a better set of tongs. It is a set of functional programming libraries. If I believe it to be useful enough for others to be interested I will release it publicly, for free, like I did Plaster (a now abandoned library for type checking, error reporting, and visualizing Arrays and Objects) and HashTable (a safe alternative to AutoHotkey's Object). I am trying to finish the documentation and rewrite all the error handling to report more useful error messages.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

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

15 Nov 2018, 08:21

Like we said before not all objects have a base object. ObjGetBase only applies to objects that can have a base object. Function Objects do not have a base object.
Creating consistency for those old objects just isn't possible in v1. Most of your concerns are adressed in v2 to some extend.
Im not sure though if you should use ObjGetBase instead of .base because you may receive inaccurate results - at least for some of my scripts.
If you want to keep working with v1 I reccomend just using Try/Catch here.
Recommends AHK Studio
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

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

15 Nov 2018, 09:07

nnnik wrote:
15 Nov 2018, 08:21
Like we said before not all objects have a base object. ObjGetBase only applies to objects that can have a base object. Function Objects do not have a base object.
Creating consistency for those old objects just isn't possible in v1. Most of your concerns are adressed in v2 to some extend.
Im not sure though if you should use ObjGetBase instead of .base because you may receive inaccurate results - at least for some of my scripts.
If you want to keep working with v1 I reccomend just using Try/Catch here.
Function objects often do have a base object. Every user-defined type will work with ObjGetBase(Object). If you define a class with a suitable Call(Args*) method, it will work just fine with ObjGetBase(Object) and dynamic calls. Apparently this is exactly what I did that led me to believe it always works. My libraries contain a large number of combinators that are defined as or wrapped in classes. The problem only arises when using built-in function objects (function objects produced directly by Func(FunctionName), the Bind(Args*) method of a function object produced directly by Func(FunctionName), or ObBindMethod(Obj, Method, Args*)).

Making function objects behave consistently should be very much possible in v1. Adding the missing properties and methods so that things produced by Func(Name) and the Bind(Args*) method would have the same interface and making every value work with ObjGetBase(Object) and ObjSetBase(Object, BaseObject) would not change the semantics of existing code. It would only make code that had not worked before work.

Many of v2's changes (e.g. is and anonymous functions) would be possible to backport to v1 without breaking anything.

I did use the base property in the past. I stopped because of it tripping some meta-functions on some of my classes and worrying about corner cases with code outside my control. I have been using try and catch since I rewrote my code to make it work with the problematic input.

v2 does not seem to address most of my concerns. Recently, it seems, the decision has been made to actually report most errors, on by default even. While that is only one complaint of mine, it is by far the greatest source of my frustration. The built-in type checking code would have saved me from having to write my own. Nothing seems to have been done about the inconsistency or conflation throughout the language, so, despite acceptable error handling, I would still be writing a lot of type checking code to abstract over these problems. The anonymous functions would be nice, but I am concerned about how well they will work without tracing garbage collection. The GUI support seems to be slightly improved. That is all I have seen that is relevant to me. This is not enough to convince me to use a moving target.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

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

15 Nov 2018, 10:01

Function objects often do have a base object.
Function objects are all objects returned by Func(). All other objects implement the "Callable" interface.
They are therefore callables not function objects. Function objects don't have a base object they have a function that handles all acceses.
so that things produced by Func(Name) and the Bind(Args*) method would have the same interface
No it isn't - I checked the source code myself. Bind wraps around any callable. Not every callable exposes the information necessary to provide the same interface as function objects.
If we want to make the interfaces the same we either have to limit bind on function objects (and the newly created boundFunc objects which would be the same) and remove all other objects.
Or we would have to remove features from function objects. Beither is an option in v1 since those are breaking changes.
ObjGetBase(Object) for all objects
What should ObjectGetBase return for COMObjects? What would ObjSetBase do with COMObjects?
What kind of base Object would a function object return?

Something you have to know about all AHK objects is that not every Object may be a build in AHK Object but each and every single Object in AHK is a COM Object.
What you suggest would require a complete rewrite of the source to invert the dependency. It would also remove some COM features that are documented.
Therefore it is not possible to introduce these features in v1.
Recommends AHK Studio
[Shambles]
Posts: 100
Joined: 20 May 2014, 21:24

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

15 Nov 2018, 21:57

nnnik wrote:
15 Nov 2018, 10:01
Function objects often do have a base object.
Function objects are all objects returned by Func(). All other objects implement the "Callable" interface.
They are therefore callables not function objects. Function objects don't have a base object they have a function that handles all acceses.
so that things produced by Func(Name) and the Bind(Args*) method would have the same interface
No it isn't - I checked the source code myself. Bind wraps around any callable. Not every callable exposes the information necessary to provide the same interface as function objects.
If we want to make the interfaces the same we either have to limit bind on function objects (and the newly created boundFunc objects which would be the same) and remove all other objects.
Or we would have to remove features from function objects. Beither is an option in v1 since those are breaking changes.
ObjGetBase(Object) for all objects
What should ObjectGetBase return for COMObjects? What would ObjSetBase do with COMObjects?
What kind of base Object would a function object return?

Something you have to know about all AHK objects is that not every Object may be a build in AHK Object but each and every single Object in AHK is a COM Object.
What you suggest would require a complete rewrite of the source to invert the dependency. It would also remove some COM features that are documented.
Therefore it is not possible to introduce these features in v1.
Most programming languages do use common superclasses to determine the type of a value, if you try to compare its type instead of just use the same members on it. I would be okay with that in a programming language designed with a coherent type hierarchy. This does not describe the situation with AutoHotkey. I hope it will, someday, soon.

Dynamically type checked programming languages with a coherent type hierarchy rarely make it necessary to determine the type of a value. Depending on polymorphism is preferred. The same interface provides the same functionality for all types (if it is Fooable it will have the Foo method), so you do not need to even worry whether the member will exist. If the interface does not exist, you must have been passed an unusable value, as opposed to having been passed a value with an incompatible but equivalent interface that you could have used if only you had recognized it (e.g. I get the length of an array with ObjLength(Array) or Array.Length(), but I get the length of a string with StrLen(Str). This is why comparing the type and dispatching to the right code is necessary in AutoHotkey.). They also usually report all errors in a helpful way. This does not describe the situation with AutoHotkey. I hope it will, someday, soon.

I am not sure what you checked in the source code, but I will defer to you on that. I have attempted to read it several times and was scared away by the comments and structure. I believe you when you say that not all equivalent constructs preserve the same information. I do not believe it is impossible to preserve the same information for all equivalent objects constructed by AutoHotkey. In short, I believe you that it is broken, but I do not believe that is a valid reason to not fix it. If the AutoHotkey source does not cause something to be exposed that should be exposed, it should be changed to expose that thing. Other programming languages (e.g. Smalltalk, Python, etc.) manage to keep track of the same information, most of the time (e.g. Python cannot refer you to the Python source code for built-in constructs written in C), for both their built-in and user-defined constructs. I do not have these problems in other programming languages.

For example, MinParams and MaxParams are not provided on BoundFunc objects. BoundFunc objects are normally produced by calling the Bind(Args*) method on a function object produced via Func(FunctionName), which does contain this information, or from ObjBindMethod(Obj, Method, Args*), which either operates on a built-in type that could contain this information or a user-defined type which does contain this information. Preserving this information and performing subtraction is not impossible.

It is definitely possible to make the Bind(Args*) method reliably return a function object with a Bind(Args*) method. I know because I have already written code that does that, and I did not even need to alter the AutoHotkey interpreter. I just wrap function objects in a sanity preserving class that behaves like a function object.

If COM objects, other than the ones AutoHotkey exposes, do not expose the necessary information, that might be a valid excuse to not provide it for external COM objects, only. It might also be a good reason to have external COM objects under a separate part of the type hierarchy in v2 so that we can recognize "that is an external COM object, so I should not try to ____ it". I am skeptical that this is the case. PowerShell is extremely good at interrogating COM objects. For example, it can reliably enumerate their members, including returning information about their parameters. PowerShell is open source, so if the developers are enamored enough with COM to try to fit everything into its mold, they could look at its source to see how the magic is made.

I would expect ObjGetBase and ObjSetBase to return or set (respectively) the default base object for COM objects and function objects. Whatever member could not be found on the COM object or function object would be handled, if it was defined, by the default base object, at least when used from AutoHotkey (I would not expect external code to recognize it on the COM object). The default base object already works this way, with these limitations, for strings (including numbers).

I am surprised to hear that every object in AutoHotkey is a COM object. AutoHotkey's Objects do not act like Scripting.Dictionary and AutoHotkey Arrays do not act like SAFEARRAY. This also seems like a poor excuse for inconsistency. If anything, working with COM objects should be seamless in AutoHotkey, while in reality it is much easier in PowerShell than AutoHotkey. I am sure the developers can expose everything as a COM object, and they can also choose what is to be exposed. They should be able to make what they expose consistent and avoid conflation. For example, iterating over a COM SAFEARRAY should put the array's values in the Value variable, not the Index variable, like it currently does.
iseahound
Posts: 1444
Joined: 13 Aug 2016, 21:04
Contact:

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

15 Nov 2018, 23:04

Try to make your arguments more succinct for future readers. I agree with some of your grievances namely:
  • "".base is clearly an object, but is not really an object.
  • Function Objects are not function objects.
Number 1 is easy. What is being defined is the global string object or something similar. Generally any code that calls "".base is creating its own domain-specific language, which is messy and is clearly an outgrowth of the current v1. It should be merged with the regular notion of an object, but how to do this? Allowing users to override default behavior is dangerous and doesn't really promote cross script compatibility. The only outcome I see is that this behavior should be banned in v2. There needs to be a replacement.

Number 2 is very bad. The notion of a function object is like a meta object of a function in AutoHotkey. That's a round about way of implementing behavior, specifically Func("some_function").Bind(args*). A function with a fewer number of arguments should return a function with partially bound arguments by default. The problem is that BoundFuncs and Function Objects feel second class in AutoHotkey. They need to be called using like %BoundFunc%() or BoundFunc.call().

And finally there is the whole issue of Error Handling vs. Error Propagation. I still don't know which I prefer, but some of us here are in favor of throw when divide by 0, and others with return a null object like "", or something that can be caught in the future.
iseahound
Posts: 1444
Joined: 13 Aug 2016, 21:04
Contact:

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

15 Nov 2018, 23:31

Finally if you look towards Category Theory the notion of a Function is defined as a map from A to B. There could be another Function in some other world defined as F(A) to F(B). A functor would then be a mapping of (A → B) → (F(A) → F(B)). What does this mean?

Imagine I have an image saved as a PNG and I want to convert it to a JPEG. I write some function that converts input_image : PNG → output_image : JPG. Now I have a PNG file. But in some other world I am dealing with base64 data, not files. Clearly my function from PNG → JPG is cool, but it only does PNG : file → JPG : file. I'll need PNG : base64 → JPG : base64 to solve my problem. But clearly I can also write 2 functions PNG1 : file → PNG2 : base64 and JPG1 : base64 → JPG2 : base64. If this is true, then we can generalize (via induction) that there exists a functor file → base64.

If you draw out the above example you get a square. Now if there exists an arrow from a to b and another arrow from b to c, then there must exist an arrow from a to c. Therefore there exists a function PNG : file → JPG : base64.

This defines a functor, which is a function between functions. A natural transformation is a function between functors. And so on.

The problem is that AHK defines introspection of functions via Func("StrLen") when actual functors defined in objects are introspected via Object(some_object). This is more of a limitation of pure mathematics implemented on a computer, so AHK could make it better.

Return to “Wish List”

Who is online

Users browsing this forum: No registered users and 47 guests