PClough

About the function data type

8 posts in this topic

#1 ·  Posted (edited)

Hi!

I've never had to use the function data type so far.  But having to develop a data structure involving lots of indirect calls, I had to have a closer look. The possibility of assigning a function to a variable is a powerful tool. However, I came up against a problem when it comes to error handling:  if a function is explicitely assigned to a variable,  the IsFunc built-in fonction makes it possible to test that the function actually exists.  However, if the function name is built by the program on the fly, there is no way of checking that the function exists, because IsFunc requires a parameter which is a function and does not work if you use its name instead.

After numerous tests, trials and errors, I came up with a function that solves the problem.  My problem is that I have no idea why it does and it would be useful if someone could help me to understand, because it is obvious that I do not understand the operation of this function data type.  Here is my snippet with an example:

 

#cs Func _IsFunc(Const $func)
Check whether a function exists - $func can either contain the function itself or its name as a string
Returns 0 if the function does not exist, 1 if it is a user function, 2 if it is a built-in function
#ce
Func _IsFunc(Const $func)
  Local $x = IsString($func) ? Execute("IsFunc(" & $func & ")") : IsFunc($func)
  If @error Then $x = 0
  Return $x
EndFunc   ;==>_IsFunc

Global $a = Test, $b = "Test"

; both these calls work
Call($a, "function")
Call($b, "string")

MsgBox(0,"", "function            : " & _IsFunc($a) & " - " & IsFunc($a) & @CRLF & _
             "funcName(function)  : " & _IsFunc(FuncName($a)) & " - " & IsFunc(FuncName($a)) &  @CRLF & _
             "string              : " & _IsFunc($b) & " - " & IsFunc($b) & @CRLF & _
             "string non existing : " & _IsFunc("TestDoesNotExist") & " - " & IsFunc("TestDoesNotExist") & @CRLF & _
             "built-in func       : " & _IsFunc(Call) & " - " & IsFunc(Call) & @CRLF & _
             "built-in func name  : " & _IsFunc("Call") & " - " & IsFunc("Call") & @CRLF)

Func Test($par)
  ConsoleWrite("this is an empty function called by Call with a " & $par & " as parameter" & @CRLF)
EndFunc

The _IsFunc function does the trick.  But I have no idea why.  Strangely enough, though, the original IsFunc works if it is run via Execute, but only to an extent: when parameter $func does not exist as a function (whether it is a function variable or a function name) Execute generates an error - and only in these cases.  Of course, it's convenient because this allows me to catch these cases.  But why this is, is also a mystery.

Any clue would help...

 

Edited by PClough

Share this post


Link to post
Share on other sites



#2 ·  Posted

I don't see what isn't clear.

IsFunc($a) is directly interpreted AutoIt code.

Execute("IsFunc(" & $b & ")") relies on reflection. "IsFunc(" & $b & ")" is evaluated first, yielding "IsFunc(Test)" which is then executed as in the first case.


This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites

#3 ·  Posted

8 minutes ago, jchd said:

I don't see what isn't clear.

IsFunc($a) is directly interpreted AutoIt code.

Execute("IsFunc(" & $b & ")") relies on reflection. "IsFunc(" & $b & ")" is evaluated first, yielding "IsFunc(Test)" which is then executed as in the first case.

First of all, what is not clear is the function data type itself: it is not documented in the "data type" page of the help file (to which the doc of the IsFunc refers). I think I understand the way it is used but not its status as a data type compared to the others.  Is it some kind of a pointer?  What automatic conversion is applied to such a type in a string concatenation, for instance?  Is it automatically typecast to its name? This is a type which appears in just two built-in functions, and even then the way it is used by Call is hardly explicit in the doc. Are there other functions which use it and how?  I did a search in the doc without getting any useful result.

Second, I understand that IsFunc($a) is directly interpreted, but I am not sure what you mean by "relies on reflection", although I do understand the rest, which makes sense. But this still does not explain why Execute generates an error when IsFunc("TestDoesNotExist") returns 0.

Thanks for your help, though

 

Share this post


Link to post
Share on other sites

#4 ·  Posted

Reflection is the capability for a program written in a given computer language to create code on the fly and/or to examine its own code.

AutoIt can do the former action thru Execute but not the latter.

4 minutes ago, PClough said:

But this still does not explain why Execute generates an error when IsFunc("TestDoesNotExist") returns 0.

Run Execute(0) to see why.

And yes, the helpfile lacks information about the new function datatype as it was added shortly before release and we didn't have time to change the help file material.

VarGetType returns "Function" or "UserFunction" on variables assigned core or UDF functions resp.

Global $a = _Test, $b = "_Test", $c = MsgBox

; both these calls work
Call($a, "function")
Call($b, "string")

; Call() can be dispensed of, since $a is a function datatype:
$a("function")

ConsoleWrite("$a is a " & VarGetType($a) & @LF)
ConsoleWrite("$b is a " & VarGetType($b) & @LF)
ConsoleWrite("$c is a " & VarGetType($c) & @LF)

Func _Test($par)
  ConsoleWrite("this is an empty function called by Call (or not) with " & $par & " as parameter" & @CRLF)
EndFunc

 


This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

1 hour ago, jchd said:

Reflection is the capability for a program written in a given computer language to create code on the fly and/or to examine its own code.

AutoIt can do the former action thru Execute but not the latter.

Run Execute(0) to see why.

And yes, the helpfile lacks information about the new function datatype as it was added shortly before release and we didn't have time to change the help file material.

VarGetType returns "Function" or "UserFunction" on variables assigned core or UDF functions resp.

Ok, points taken and thanks for the example.  Still one last question:  the structure I want to implement requires some of the functionalities found in most OO language - i.e. a form of class structure.  I have already designed a record structure which fits all the requirements I expect to have.  The layer coming above would add methods, with the possibility of implementing simple forms of inheritance and overloading. This is the reason why I have become interested in this function data type. 

The record type model I use is somewhat similar to the DllStructure used by autoit. Except that, since I wanted to make it more flexible (without fixed length fields, in particular), without  having to transform autoit into an assembler operating on blocks of memory, each record is actually a string where all fields are converted to strings, with a structure which makes it easy to find and change them, using the language's powerful string functions.  The field definitions are stored in a global dictionary, using a simple implementation of a hash.  It works fine, quite fast in fact.  So far, so good and easy.

To add the method layer I have to store somehow the definitions and characteristics of the classes' methods on top of the classes' property definitions.  The inheritance and overloading mechanisms are easy to figure out.  The idea is that each class lives in its own module and method names follow a simple naming pattern. For example, the method "load" of class "truck" would be called _truck_load(...).  Storing the characteristics and names of the methods in the record dictionary is no problem, but I don't see a way of using a string storage and at the same time storing the methods using the function data type.  To avoid redundancy between the definitions of the various classes, I need to have a mechanism which allows me to test the existence of a method by its name: if "load" does not exist in the definition of class "truck", I need to check whether it exists in the definition of its ancestor(s), say class "vehicle". Which is why I looked for a more flexible version of IsFunc using the name of a function in order to have a mechanism which would be faster than doing several lookups in the method tables of my class hierarchy.

The next and last problem (as far as I can see) is linked:  it is to overcome the fact that Call does not take ByRef parameters.  Obviously this is a problem since class methods need to be able to change the properties of the instance of the class which is calling them. The first approach I found, involves implementing a global stack in which all class instances would live, each being defined by a handle that can be passed to a method without the need for a ByRef.  This can work.  It is probably relatively slow because I have to rely on a big array of strings, but it seems workable.  The second possible approach (which prompted more questions about the function data type) would be to use a direct call without the indirection of Call.  But this would require a function funcFromNam($fname) which, given the name $fname of a function, would return the corresponding function data type value.  In that case, it would become possible to pass to this returned function value a ByRef parameter pointing to the calling instance of the class and there would be no need for the overhead of managing a global stack.

Sorry to dump on you all my problems.  But I couldn't find a shorter way of explaining them.  Thanks for any thoughts if you can spare the time.

PC

Edited by PClough

Share this post


Link to post
Share on other sites

#6 ·  Posted

You shouldn't need to use Call at all. You can create variables containing a function datatype assigned to whatever function name you want, on the fly:

Local $MyFunc = "_Te"
Execute('Assign("d", ' & $MyFunc & 'st)')
ConsoleWrite("$d is a " & VarGetType($d) & @LF)

Of course you need Func _Test(...) declared somewhere in the script, possibly with ByRef parameters.

Is that what you need? Or what am I missing?

1 person likes this

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites

#7 ·  Posted

Sorry, I should have used my brain... In fact, I just tested your suggestion using Execute and it solves the ByRef problem.  I'll have to check whether the resulting overhead is acceptable., but I can't see why not.

Thanks a lot - when all the modules are up and running I'll post them on the forum, in case they might be of some use for someone else.

PC

 

Share this post


Link to post
Share on other sites

#8 ·  Posted

Don't worry, we're all here to help.


This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now