Page 1 of 1

classic simple functions: Swap / Assign / Sign

Posted: 09 May 2019, 09:55
by jeeswg
- Swap (or VarSwap) / Assign / Sign.
- [EDIT:] And further functions here ranked by usefulness:
https://autohotkey.com/boards/viewtopic.php?f=13&t=64405&p=277017#p277017

- If built-in, you would probably use them, otherwise, you would use more verbose or cryptic code.
- They add clarity and elegance to scripts, and are more instructive, regarding intention, than the alternatives. Cf. the advantages brought by the Min/Max functions.
- (I view potential StrCount/StrRept functions as having similar advantages.)

- Swap: avoid using a temporary variable when swapping variables, simpler.
- Avoid time spent double-checking the code.
- (Perhaps also: ObjSwap (or ObjSwapKeys).)

- Assign (lower priority): saves writing out long variable names twice.
- Assign could also be used to write directly to A_ variables, making various SetXXX commands redundant. (Or are those A_ variables going to become writable in AHK v1 at some point?)

- Sign: avoid cryptic (n > 0) - (n < 0) or using a ternary operator.
- Simplifies longer expressions that check the sign.
- (An alternative to Sign(Num) would be NumCompare(Num, 0).)

- Some example code:

Code: Select all

q:: ;swap values
var1 := "a", var2 := "b"
Swap(var1, var2)
MsgBox, % var1 " " var2

oArray := ["a", "b"]
ObjSwap(oArray, 1, 2)
MsgBox, % oArray.1 " " oArray.2
return

Swap(ByRef var1, ByRef var2)
{
	temp := var1
	var1 := var2
	var2 := temp
}

ObjSwap(obj, key1, key2)
{
	temp := obj[key1]
	obj[key1] := obj[key2]
	obj[key2] := temp
}

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

w:: ;assign
var := "old value"
MsgBox, % var
old := Assign(var, "new value")
MsgBox, % var " " old
return

Assign(ByRef var, value)
{
	temp := var
	var := value
	return temp
}

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

e:: ;sign
MsgBox, % Sign(-123) " " Sign(0) " " Sign(123)
return

Sign(num)
{
	return (num > 0) ? 1 : (num < 0) ? -1 : 0
	;return (num > 0) - (num < 0)
}

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

Re: Swap / ObjSwap / Assign / Sign

Posted: 10 May 2019, 18:54
by kczx3
Can't say I've ever had a need for any of these.

Re: Swap / ObjSwap / Assign / Sign

Posted: 10 May 2019, 19:33
by jeeswg
- I've essentially completed my Wish List 2.0.
- These, and IsNum/Num, in another thread, are the functions I am 50/50 on.

- Swaps are common in mathematical/sort algorithms.
- I'd rather use some kind of Swap function, than 3 assignments.
- One use is for start/end points, to make sure one variable contains the smaller number, e.g. in date functions.

- Sign is a built-in function in Excel for example. And is a counterpart to Abs.
- It is also in the JavaScript Math object.
Math - JavaScript | MDN
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math
- It's useful in relation to direction i.e. increments/decrements, handling signs e.g. with Mod, and functionality re. Floor/Round/Ceil.
- It's useful in date functions, to increment/decrement dates.
- It's used in the erf function, in relation to the gamma function (related to the cdf function and the normal distribution):
Error function - Wikipedia
https://en.wikipedia.org/wiki/Error_function
- I would be interested to hear of any other potential uses.

- I wouldn't mind too much if Assign wasn't implemented, since varcopy := var, var := "new value" is arguably more explicit than varcopy := Assign(var, "new value").
- However, (a) if A_ variables are not to be made writable in AHK v1, i.e. A_XXX := "new value", this would be a good alternative, (b) it might be useful in expressions, it's just that, since we haven't had it, people haven't thought to use it.
- There's different ways an Assign function could be implemented. Here's the AutoIt version:
Function Assign
https://www.autoitscript.com/autoit3/docs/functions/Assign.htm

Re: Swap / ObjSwap / Assign / Sign

Posted: 12 May 2019, 23:31
by jeeswg
In general, it's good when there is a one-to-one mapping between the idea and the code. Versus logic that is lower-level than how you thought it.

Here is a Swap function and two further convenience gains:

E.g. swap variables:

Code: Select all

;more intuitive:
Swap(var1, var2)

;less intuitive (3 assignments):
temp := var1, var1 := var2, var2 := temp
E.g. a Range function:

Code: Select all

;more intuitive:
for _, vValue in Range(-10, 10, 0.5)

;less intuitive (low-level workaround):
Loop, 41
	vValue := -10+(A_Index-1)*0.5
E.g. easily increment/decrement object values:
(Although a way to change the default value, from a blank string to 0, would be a better solution.)

Code: Select all

;more intuitive (method):
oArray := new ClassSetDefaultValue
oArray.SetDefaultValue(0)
oArray.key++
MsgBox, % oArray.key

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

;more intuitive (function):
oArray := new ClassSetDefaultValue
ObjSetDefaultValue(oArray, 0)
oArray.key++
MsgBox, % oArray.key

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

;also intuitive:
oArray := {}
ObjInc(oArray, "key")
MsgBox, % oArray.key

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

;less intuitive:
oArray := {}
vKey := "key"
if !oArray.HasKey(vKey)
	oArray[vKey] := 1
else
	oArray[vKey]++
MsgBox, % oArray.key

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

ObjSetDefaultValue(obj, default)
{
	obj.SetDefaultValue(default)
}

class ClassSetDefaultValue
{
	__New(default)
	{
		this.default := _default
	}
	__Get()
	{
		return this._default
	}
	SetDefaultValue(default)
	{
		this._default := default
	}
}

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

ObjInc(oArray, vKey)
{
	if !oArray.HasKey(vKey)
		oArray[vKey] := 1
	else
		oArray[vKey]++
}

ObjDec(oArray, vKey)
{
	if !oArray.HasKey(vKey)
		oArray[vKey] := -1
	else
		oArray[vKey]--
}

;==================================================
It's so common to increment/decrement keys, that it should be easier than a four-liner. Like Swap, it's not super-difficult to recreate the logic every time you need it, but it does require a reasonable/notable amount of thinking and checking time, and the repeated use of variable names that vary each time (limiting the utility of hotstrings in this case).

Re: Swap / ObjSwap / Assign / Sign

Posted: 14 May 2019, 04:48
by jeeswg
VARXXX FUNCTION SUITE
- I was thinking of a potential 'suite' of VarXXX functions: VarExist, VarGetName, VarSet(/Assign), VarSwap.
- Some other possible VarXXX functions are mentioned here:
VarSetCapacity - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=37&t=64493

ASSIGN TO ALLOW WRITABLE A_ VARIABLES
- Since I was informed here, that AHK v1 is unlikely to have writable A_ variables. E.g. A_StringCaseSense := 1.
A_ variables - Page 2 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=37&t=41870&p=276824#p276824
- I thought a good two-way compatible workaround would be to have an Assign/VarSet function.
- In my version below, you have to pass A_ variables as strings, but, if it was built-in, or if there were a VarGetName function, you could pass them directly.
- Note: VarExist/VarSwap functions would accept variables directly (and would possibly accept variable names as strings also).

Code: Select all

q:: ;test Assign
vText := "value 1"
MsgBox, % vText
vTextOld := Assign(vText, "value 2")
MsgBox, % vTextOld "`r`n" vText

MsgBox, % A_StringCaseSense
vSCS := Assign("A_StringCaseSense", "On")
MsgBox, % vSCS "`r`n" A_StringCaseSense
return

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

;note: accepts normal variables ByRef
;note: accepts A_ variables as strings
Assign(ByRef vVar, vValue)
{
	local
	static vAllowMainWindow := !A_IsCompiled ;close approximation to A_AllowMainWindow

	;handle normal variables:
	if IsByRef(vVar)
	{
		vTemp := vVar
		vVar := vValue
		return vTemp
	}
	else if !(SubStr(vVar, 1, 2) = "A_")
		return

	;not handled:
	;A_Args (object)
	;A_IconFile (set by TraySetIcon)
	;A_IconNumber (set by TraySetIcon)
	;A_Index
	;A_TrayMenu (object)

	;partially handled:
	;A_AllowMainWindow (can set but cannot get)

	;handle A_ variables:
	if (vVar = "A_AllowMainWindow")
	{
		vRet := vAllowMainWindow
		if A_IsCompiled
			vAllowMainWindow := vValue
	}
	else
		vRet := %vVar%

	if (vVar = "A_AllowMainWindow")
		Menu, Tray, % vValue ? "MainWindow" : "NoMainWindow"
	else if (vVar = "A_ControlDelay")
		SetControlDelay, % vValue
	else if (vVar = "A_CoordModeCaret")
	|| (vVar = "A_CoordModeMenu")
	|| (vVar = "A_CoordModeMouse")
	|| (vVar = "A_CoordModePixel")
	|| (vVar = "A_CoordModeToolTip")
		CoordMode, % SubStr(vVar, 12), % vValue
	else if (vVar = "A_DefaultMouseSpeed")
		SetDefaultMouseSpeed, % vValue
	else if (vVar = "A_DetectHiddenText")
		DetectHiddenText, % vValue
	else if (vVar = "A_DetectHiddenWindows")
		DetectHiddenWindows, % vValue
	else if (vVar = "A_FileEncoding")
		FileEncoding, % vValue
	else if (vVar = "A_IconHidden")
		Menu, Tray, % vValue ? "NoIcon" : "Icon"
	else if (vVar = "A_IconTip")
		Menu, Tray, Tip, % vValue
	else if (vVar = "A_IsCritical")
		Critical, % vValue
	else if (vVar = "A_KeyDelay")
		SetKeyDelay, % vValue
	else if (vVar = "A_KeyDelayPlay")
		SetKeyDelay, % vValue,, Play
	else if (vVar = "A_KeyDuration")
		SetKeyDelay,, % vValue
	else if (vVar = "A_KeyDurationPlay")
		SetKeyDelay,, % vValue, Play
	else if (vVar = "A_LastError")
		DllCall("kernel32\SetLastError", "UInt",vValue)
	else if (vVar = "A_ListLines")
		ListLines, % vValue
	else if (vVar = "A_MouseDelay")
		SetMouseDelay, % vValue
	else if (vVar = "A_MouseDelayPlay")
		SetMouseDelay, % vValue, Play
	else if (vVar = "A_RegView")
		SetRegView, % vValue
	else if (vVar = "A_SendLevel")
		SendLevel, % vValue
	else if (vVar = "A_SendMode")
		SendMode, % vValue
	else if (vVar = "A_StoreCapsLockMode")
		SetStoreCapsLockMode, % vValue
	else if (vVar = "A_StringCaseSense")
		StringCaseSense, % vValue
	else if (vVar = "A_TitleMatchMode")
	|| (vVar = "A_TitleMatchModeSpeed")
		SetTitleMatchMode, % vValue
	else if (vVar = "A_WinDelay")
		SetWinDelay, % vValue
	else if (vVar = "A_WorkingDir")
		SetWorkingDir, % vValue
	return vRet
}

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

Re: Swap / ObjSwap / Assign / Sign

Posted: 15 May 2019, 03:38
by jeeswg
SUMMARY

Summary of classic convenience functionality mentioned:
And sureness for inclusion.

From thread title:
Swap(/VarSwap) [100%]
ObjSwap(/ObjSwapKeys/ObjSwapValues) [50%]
Assign(/VarSet) [50%, the key point is: writable A_ variables or *some* function to assign A_ variables]
Sign [related: NumCompare] [100%]

Also mentioned:
IsNum (is float/is integer/is string that looks numeric) [100%] [repeated '(var is "number")' seems too verbose]
Num (to number) [50%]
ObjSetDefaultValue [or another name, or: ObjDec/ObjInc] [100%, by *some* means]
Range [100%]
StrCount [100%]
StrRept [100%]
VarExist(/IsVar) [100%]
VarGetName [100%]

Also:
VarIsInit(/IsInit) [100%]
C++: AHK source code: VarIsInit - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=75&t=65308

Also, 'FUNCTIONS (SIMPLE WORKHORSE FUNCTIONS)' (Base64Get/Base64Put/HexGet/HexPut, Between/FloorMod/Pow, NoOp, StrJoin):
Wish List 2.0 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=13&t=36789

Further, StrSetCapacity/StrSetSize:
VarSetCapacity - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=37&t=64493

Re: classic simple functions: Swap / Assign / Sign

Posted: 13 Jun 2019, 14:02
by jeeswg
ASSIGN: CYCLE VALUES
Here are some nice examples for Assign and ObjAssign:

Code: Select all

q:: ;cycle values via Assign/ObjAssign
v1 := "a", v2 := "b", v3 := "c", v4 := "d", v5 := "e"
Loop, 11
{
	MsgBox, % Format("{} {} {} {} {}", v1, v2, v3, v4, v5)
	Assign(v5, Assign(v4, Assign(v3, Assign(v2, Assign(v1, v5)))))
}

MsgBox

o := ["a", "b", "c", "d", "e"]
Loop, 11
{
	MsgBox, % Format("{} {} {} {} {}", o*)
	ObjAssign(o, 5, ObjAssign(o, 4, ObjAssign(o, 3, ObjAssign(o, 2, ObjAssign(o, 1, o.5)))))
}
return

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

w:: ;swap object key values via ObjAssign
obj1 := {}
obj2 := {}

obj1.key1 := "1"
obj2.key2 := "2"
MsgBox, % obj1.key1 " " obj2.key2 ;1 2
ObjAssign(obj1, "key1", ObjAssign(obj2, "key2", obj1.key1))
MsgBox, % obj1.key1 " " obj2.key2 ;2 1

obj1.key1 := "1"
obj2.key2 := "2"
MsgBox, % obj1.key1 " " obj2.key2 ;1 2
temp := obj1.key1, obj1.key1 := obj2.key2, obj2.key2 := temp
MsgBox, % obj1.key1 " " obj2.key2 ;2 1
return

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

Assign(ByRef var, value)
{
	local temp
	temp := var
	var := value
	return temp
}

ObjAssign(obj, key, value)
{
	local temp
	temp := obj[key]
	obj[key] := value
	return temp
}

;==================================================
Note: I've revised/expanded earlier posts.

Re: classic simple functions: Swap / Assign / Sign

Posted: 25 Jul 2019, 19:32
by jeeswg
A lot of interest in 'ObjSetDefaultValue':

python - Dictionaries and default values - Stack Overflow
https://stackoverflow.com/questions/9358983/dictionaries-and-default-values

python - Why dict.get(key) instead of dict[key]? - Stack Overflow
https://stackoverflow.com/questions/11041405/why-dict-getkey-instead-of-dictkey