custom function direct to object

Propose new features and changes
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

custom function direct to object

27 Apr 2019, 14:35

In my Wish List 2.0, I mentioned this, for AHK v1/v2, with custom sort functions in mind, so that if I shared a script, with a custom sort function, it wouldn't clash with an existing function name.
> CUSTOM FUNCTION DIRECT TO OBJECT
(and custom class direct to object)

- something like this that can handle a complete function cf. fat arrow functions:

Code: Select all

oFunc := NewFunc(arg1, arg2, arg3)
{
	return arg1 arg2 arg3
}
- the same may be potentially useful for classes oClass := class ...
- otherwise you can get clashes with existing functions/classes for simple temporary code

I've since seen that this can also be very useful for functions for filtering lines (keeping/omitting lines), and modifying(/not modifying) lines.

For permanent functions, I'd rather store them in one place. For temporary functions, I'd rather keep the code together with other relevant code, not have proper named functions dotted about the place in random locations, and not pollute the global namespace, hence the advantage of storing them direct to object.

Here are some examples for filtering/modifying/sorting:

Code: Select all

q:: ;filter/modify text using a filter/modifier function - keep/modify if contain vowels

vText := "
(
abcde
fghij
klmno
pqrst
uvwxy
z
)"

oFilter := Func("MyFilter")
MyFilter(vText)
{
	return !!RegExMatch(vText, "i)[aeiou]")
}

oModifier := Func("MyModifier")
MyModifier(vText)
{
	return (RegExMatch(vText, "i)[aeiou]") ? "`t" : "") vText
}

MsgBox, % LineFilter(vText, oFilter)
MsgBox, % LineModifier(vText, oModifier)
return

LineFilter(vText, oFunc)
{
	local
	vOutput := ""
	VarSetCapacity(vOutput, StrLen(vText)*2+2*2)
	Loop, Parse, vText, `n, `r
	{
		if %oFunc%(A_LoopField)
			vOutput .= A_LoopField "`r`n"
	}
	return SubStr(vOutput, 1, -2)
}

LineModifier(vText, oFunc)
{
	local
	vOutput := ""
	VarSetCapacity(vOutput, StrLen(vText)*2+2*2)
	Loop, Parse, vText, `n, `r
		vOutput .= %oFunc%(A_LoopField) "`r`n"
	return SubStr(vOutput, 1, -2)
}

;==================================================

w:: ;sort using a custom function

vText := "
(
Item 100
Item 20
Item 3
)"

;the Sort function would be defined here
;direct to an object (to not interfere with the global namespace)

Sort, vText
MsgBox, % vText

Sort, vText, F SortStrCmpLogical
MsgBox, % vText
return

SortStrCmpLogical(vTextA, vTextB, vOffset) ;for use with AHK's Sort command
{
	local
	vRet := DllCall("shlwapi\StrCmpLogicalW", "WStr",vTextA, "WStr",vTextB)
	if (vRet = 0)
		return -vOffset
	else
		return vRet
}

;==================================================

Here is some example code for doing something similar in JavaScript. You can save the code to an htm file, and open the htm file, to run it.

Code: Select all

<script>

//5+5=10
//5-5=0
//5*5=25
//5/5=1
//5**5=3125

for(i = 1; i <= 1; i++) //loop 1 time
{
	var myfunc = function(num1, num2)
	{
		return num1 + num2;
	}
	confirm(myfunc(5, 5));

	var myfunc = function(num1, num2)
	{
		return num1 - num2;
	}
	confirm(myfunc(5, 5));

	var myfunc = function(num1, num2)
	{
		return num1 * num2;
	}
	confirm(myfunc(5, 5));

	var myfunc = function(num1, num2)
	{
		return num1 / num2;
	}
	confirm(myfunc(5, 5));

	var myfunc = function(num1, num2)
	{
		return Math.pow(num1, num2);
	}
	confirm(myfunc(5, 5));
}

</script>

Thanks for reading.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: custom function direct to object

27 Apr 2019, 16:46

An anonymous function would either omit the name or use the keyword Func. It would not create a "new" function (I guess that may be what the name you gave it is intended to imply). Whether named or not, whether embedded in an expression or not, the function is created at load time and you merely store a reference at runtime (unless it's a closure). It may create a Closure, so omitting the name may be better.

This offers very little over the current support of nested functions. It saves coming up with a unique name for each function, but on the other hand, naming the function is useful for debugging and makes the code more self-documenting. Nested functions do not "pollute" the global namespace.

Your JavaScript example is not the best; I suppose we just have to imagine that the function needs more than one line of code in its body. In this example, both in modern JavaScript and in AutoHotkey, you would be better served with fat arrow functions.

Java has anonymous classes and JavaScript has class expressions. Before such a thing can be useful, the parser must be able to handle declaring a class inside a function. The current implementation can't handle this, let alone parsing a full class (or function) body within an expression.

Anonymous functions, nested classes and anonymous classes were already planned, but they are a long way off.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: custom function direct to object

27 Apr 2019, 17:29

- Thanks for your response.
- (Yes, I'd expect it to pass a function reference each time. Not create a new function each time.)
- 'NewFunc' / 'DefFunc', or any better name. (JavaScript called it 'function', but we already have 'Func'.)
- I was hoping this might be relatively simple to implement for AHK v1/v2, e.g. each unnamed function would be given a name, and you'd in effect have syntax sugar for: oFunc := Func("UnnamedFunc1") etc.
- (I chose simple examples to demonstrate the principles. A large number of use cases would be too complex for fat-arrow functions.)

- Cf. existing AHK v2 functionality.
- These are more newbie-friendly and powerful than fat-arrow functions. (With this technique available, people would have a more readable alternative to trying to squash too much into a single fat-arrow function. And an alternative to writing auxiliary functions to boost the usefulness of fat-arrow functions.)
- Closures/nested functions pollute the global namespace. (The functions that nested functions are within, pollute the global namespace. In AHK v1, I could use methods inside classes, same pollution problem.)
- Closures, nested functions, and fat-arrow functions are AHK v2 only. This would be a good AHK v1/v2 solution.
- By definition, you can only have nested functions, within functions. These can be used globally.
- It's OK to have functions without names, fat-arrow functions don't have names. And I'd use this technique for bits of code that I decided I didn't want to have names.
- If I wanted to do debugging, 'DefFunc' (or whatever name was chosen), would be a useful search term.
- Also, other programming languages, e.g. JavaScript, have this functionality.
- So, if relatively simple to implement, I would deem this quite valuable.

- Two btws.
- Re. debugging. We have class ClassName. I had thought that something like func FuncName() could be useful for function definitions (debugging/parsing/for newbies/consistency with other programming languages). But it's probably best to keep things as they are re. this.
- I would find it occasionally useful to be able to do something like: func alias Ceiling Ceil (e.g. Int Integer, Str String, variants of Print). E.g. when copying/pasting code to/from other languages.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: custom function direct to object

28 Apr 2019, 01:36

No, it is not simple.
I wrote:The current implementation can't handle this, let alone parsing a full class (or function) body within an expression.
There is no chance that I will implement this in v1. For starters, I would need to first re-implement nested functions, otherwise you would never be able to put an anonymous function inside another function.

jeeswg wrote:With this technique available, people would have a more readable alternative to trying to squash too much into a single fat-arrow function.
If a fat arrow function is not readable, just use a normal function definition. It is more readable than what you're suggesting; writing a non-expression function body inside an expression.
The functions that nested functions are within, pollute the global namespace.
I think that your priorities are unrealistic. If your code is not inside a function, it is probably already polluting the global variable namespace, which is much worse.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: custom function direct to object

28 Apr 2019, 13:08

otherwise you would never be able to put an anonymous function inside another function.
- Hmm, if writing anonymous functions were allowed, but only in the global namespace, and I tried to move such code into a function ... problem.
- I'm going to have to get creative with around 100-200 long-winded unique function names as I simplify my 'manipulate selected text' library. But can do so more cheerily, as you have given good reasons.
- I've now marked this proposal in my Wish List 2.0 as 'low priority'. (Although I hope that everything in the new 'MINIMAL BLUEPRINT' section is reasonably doable, and that there won't be any surprises with those.)

- Re. your last point, most people write AHK code in the global namespace. I only view 'pollution' as when a *clash* occurs, at present this only happens (to me) with function names, not variables.
- That said, global variables should be avoided. Perhaps all AHK users should be encouraged to write all of their AHK subroutines as functions.

- Btw I looked up 'fat-arrow function', unfortunately it appears common to omit the hyphen.

- Thanks for the interesting info.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: custom function direct to object

28 Apr 2019, 13:25

You could put all your functions inside a class to avoid namespace conflicts.
Recommends AHK Studio
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: custom function direct to object

28 Apr 2019, 14:05

- @nnnik: For some situations, that's a solution.
- Here's an idea of the situation I'm faced with.
- Prepend the date modified to lines, with old-style code and new-style code for comparison.

Code: Select all

q:: ;functions to modify text
;vItem := "filmod"
vItem := "filmodnew"
Clipboard := A_AhkPath "`r`n" "`r`n" A_AhkPath "x"

if vItem in filmod,patmod
{
	vOutput := ""
	;vText := JEE_GetSelectedText()
	vText := Clipboard
	Loop, Parse, vText, `n, `r
	{
		vPath := A_LoopField
		if (vPath = "")
			continue
		FileGetTime, vDateM, % vPath, M
		vOutput .= vDateM "`t" vPath "`r`n"
	}
	Clipboard := vOutput
	MsgBox, % vOutput
	return
}

if vItem in filmodnew,patmodnew
{
	;vText := JEE_GetSelectedText()
	vText := Clipboard
	ModLine_FileGetDateMod(vPath)
	{
		local
		FileGetTime, vDateM, % vPath, M
		return vDateM "`t" vPath
	}
	Clipboard := vOutput := LineModifierSkipBlanks(vText, Func("ModLine_FileGetDateMod"))
	MsgBox, % vOutput
	return
}

return

;==================================================

LineModifierSkipBlanks(vText, oFunc)
{
	local
	if !IsObject(oFunc)
		oFunc := Func(oFunc)
	vOutput := ""
	VarSetCapacity(vOutput, StrLen(vText)*2+2*2)
	Loop, Parse, vText, `n, `r
		if !(A_LoopField = "")
			vOutput .= %oFunc%(A_LoopField) "`r`n"
	return SubStr(vOutput, 1, -2)
}

;==================================================
- I have multiple code sections like that, that use Loop Parse, and am considering wrapping the Loop Parse inside a function.
- You may have noticed that code-wise, I haven't saved much space.
- There are multiple slight variations to what I might/might not do.
- One disadvantage of not having anonymous functions is that if I rename the function, I have to rename the reference to it lower down.
- Btw usually I like to keep functions separate from code, in a library. But in these cases, I'd like the code to remain where it is. The code for each 'code section', in one place. E.g. even with a really long function name, what it does may not be 100% explained (or sufficient comments would be as long as the code). Or, I may want to tweak it/check it often. Or, I may want to quickly grab the code, and modify it, to share on the forums.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Return to “Wish List”

Who is online

Users browsing this forum: No registered users and 18 guests