Passing too few params to a class method?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Sidola
Posts: 14
Joined: 10 Oct 2013, 14:14
Contact:

Passing too few params to a class method?

14 Jan 2014, 15:12

Quick question,

Passing too few parameters to a class method does not seem to produce any errors. Is this a bug or an intended behavior?

I did some searching, but I can only find one other post asking about this which sadly didn't have any answers.
User avatar
LinearSpoon
Posts: 156
Joined: 29 Sep 2013, 22:55

Re: Passing too few params to a class method?

14 Jan 2014, 15:54

It's certainly a known "feature". The fact that nothing has been done about it for this long implies that it's not a bug, or at least that it's not a serious enough problem to spend development time on.

If it bothers you, you can always roll your own error checking with __Call.

Code: Select all

t := new test
t.foo(1)  ;foo called
t.foo(1,2)  ;error - too many parameters
t.foo()  ;error - too few parameters
t.bar(2)  ;error - bar does not exist
t.abc(1)  ;abc called
t.def(1)  ;def called
return

class test
{
  __Call(function, parameters*)
  {
    funcRef := Func(funcName := this.__class "." function)
    if !IsObject(funcRef)  ;Check if function exists
    {
      Msgbox, 4, Error, %funcName% called but does not exist.`nContinue?
      IfMsgBox Yes
        return
      else
        ExitApp
    }
    if (parameters.MaxIndex()+1 < funcRef.MinParams)  ;Check if there are enough parameters
    {
      Msgbox, 4, Error, %funcName% called with too few parameters.`nContinue?
      IfMsgBox Yes
        return
      else
        ExitApp
    }
    if (parameters.MaxIndex()+1 > funcRef.MaxParams && !funcRef.IsVariadic)  ;Check that there aren't too many parameters
    {
      Msgbox, 4, Error, %funcName% called with too many parameters.`nContinue?
      IfMsgBox Yes
        return
      else
        ExitApp
    }
    return funcRef.(this, parameters*) ;Everything is good so call it
  }

  ;Nothing below here is important, these functions just display their parameters when called.
  foo(p1)
  {
    Msgbox % "Foo called with: " p1
  }

  abc(p*)
  {
    for k,v in p
      params .= "`n" v
    Msgbox % "abc called with:" params
  }

  def(a, b=0)
  {
    Msgbox % "def called with:`na=" a "`nb=" b
  }
}
Sidola
Posts: 14
Joined: 10 Oct 2013, 14:14
Contact:

Re: Passing too few params to a class method?

14 Jan 2014, 15:57

Thanks! I'll have a look at that.
lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: Passing too few params to a class method?

15 Jan 2014, 04:08

It is the intended behaviour, but it is being changed in v2. The same goes for dynamic function calls, which also fail silently when passed too few parameters.
Sidola
Posts: 14
Joined: 10 Oct 2013, 14:14
Contact:

Re: Passing too few params to a class method?

15 Jan 2014, 10:44

Sweet, meaning they will all return errors naturally?

Also, __Call is working great for all my methods except for the constructor, is there a way to include it in the __Call method or will I have to check the param count directly inside the constructor?
User avatar
JnLlnd
Posts: 487
Joined: 29 Sep 2013, 21:29
Location: Montreal, Quebec, Canada
Contact:

Re: Passing too few params to a class method?

28 Jan 2019, 18:08

LinearSpoon wrote:
14 Jan 2014, 15:54
It's certainly a known "feature". The fact that nothing has been done about it for this long implies that it's not a bug, or at least that it's not a serious enough problem to spend development time on.

If it bothers you, you can always roll your own error checking with __Call.
Until v2 is available, this tip is very helpful. Thanks LinearSpoon. I made some changes to it in order to support the situation where a function expect no parameter. Also, I moved some of the code to a function outside of the class to make it easily re-usable by inserting only a 5-lines __Call() function in each class. And I made the error messages more verbose to help locate the wrong function call.

Code: Select all

#SingleInstance force

OneClass := new MyClass()

result := OneClass.MyFunction("1", "2", "3") ; too many parameters
result := OneClass.MyFunction("1") ; too few parameters
result := OneClass.MyFunction("1", "2") ; no error message
result := OneClass.MyFunction() ; too few parameters
result := OneClass.NotAFunction() ; does not exist

ExitApp

class MyClass
{
	__New() ; missing parameter would not be detected
	{
	}
	
	MyFunction(one, two)
	{
		MsgBox, %A_ThisFunc% called with parameters: %one%, %two%
	}
	
	;-- Insert in each class ---------------------------------
	__Call(function, parameters*)
	; based on code from LinearSpoon https://www.autohotkey.com/boards/viewtopic.php?t=1435#p9133
	{
		funcRef := Func(funcName := this.__class "." function)
		if CheckParameters(funcRef, function, parameters*) ; if everything is good call the function, else return false
			return funcRef.(this, parameters*) ; everything is good
		else
			return
	}
	;-- Insert in each class ---------------------------------
}

CheckParameters(funcRef, funcName, parameters*)
; based on code from LinearSpoon https://www.autohotkey.com/boards/viewtopic.php?t=1435#p9133
{
	if !IsObject(funcRef) ; check if function exists
		return CheckParametersMsg(funcName, "")
	
	maxIndexFixed := (parameters.MaxIndex() = "" ? 0 : parameters.MaxIndex()) ; if no parameter, MaxIndex() returns "" instead of 0
	
	if (maxIndexFixed < funcRef.MinParams-1) ; check if there are enough parameters
		return CheckParametersMsg(funcRef.Name, "few", parameters[1], maxIndexFixed, funcRef.MinParams-1, funcRef.MaxParams-1)
	
	if (maxIndexFixed > funcRef.MaxParams-1 && !funcRef.IsVariadic) ; check that there aren't too many parameters
		return CheckParametersMsg(funcRef.Name, "many", parameters[1], maxIndexFixed, funcRef.MinParams-1, funcRef.MaxParams-1)
	
	return true
}

CheckParametersMsg(funcName, fewOrMany, firstParam := "", nbPassed := "", minExpected := "", maxExpected := "")
; based on code from LinearSpoon https://www.autohotkey.com/boards/viewtopic.php?t=1435#p9133
{
	if StrLen(fewOrMany)
		Msgbox, 4, Error, % "Function: " . funcName
			. "`nError: too " . fewOrMany . " parameters"
			. (StrLen(firstParam) ? "`nFirst parameter: " . firstParam : "")
			. "`n`nNumber Passed: " . nbPassed
			. "`nExpected Min: " . minExpected
			. "`nExpected Max: " . maxExpected
			. "`n`nContinue?"
	else
		Msgbox, 4, Error, % "Function: " . funcName
			. "`nError: function does not exist"
			. "`n`nContinue?"
	
	IfMsgBox Yes
		return false
	else
		ExitApp
}
There are still issues when "built-in" (not sure how to call them) functions like Length, _NewEnum, etc. are called for items of the class itself like OneClass[1], OneClass[2], etc. These functions are wrongly declared as missing and the functions are somehow broken. I stopped creating array items in the class itself and now create them in a class array object.
Sidola wrote:
15 Jan 2014, 10:44
__Call is working great for all my methods except for the constructor, is there a way to include it in the __Call method or will I have to check the param count directly inside the constructor?
In my tests, if the __New() does not have the expected number of parameters, it is just not executed, silently. The __Call function does not intercept this.
:thumbup: Author of freeware Quick Access Popup, the powerful Windows folders, apps and documents launcher!
:P Now working on Quick Clipboard Editor
:ugeek: The Automator's Courses on AutoHotkey

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: dipahk and 251 guests