Log in

View Full Version : How and why does this function's validation get invoked?


fvisagie
29th November 2012, 21:18
Hi All,

I'm putting together a script where the main decision variable ends up as an integer [0..n] as below. It sounds natural to use this integer with Select() to call the corresponding filter. However, when I do this, it seems ALL items in the Select() list have their validation code invoked, not just the one you want to call. I actually discovered this with real filters, but the same happens with functions here.


# "Received" parameter
Filter = "f0"

# Evaluate 'Filter'
filtnum = (Filter == "f0") ? 0 : \
(Filter == "f1") ? 1 : \
(Filter == "f2") ? 2 : 3
Assert(filtnum < 3, """'Filter' choice """" + Filter + """" is invalid""")

# Filter defaults: filter0 filter1 filter3
rad = Select( filtnum, 24, 24, 12 )
str = Select( filtnum, 10.0, 10.0, 5.0 )
thrL = Select( filtnum, 0, 0, 2 )
thrH = Select( filtnum, 0, 0, 40 )

# This works
(filtnum == 0) ? Version.filter0(rad, str) : \
(filtnum == 1) ? Version.filter1(rad, str) : \
(filtnum == 2) ? Version.filter2(rad, str, thrL, thrH) : \
Assert(false, "This shouldn't happen")

# This fails with "filter2: radius must be < 16", although filter2() should never be invoked
Select(filtnum, \
Version.filter0(rad, str), \
Version.filter1(rad, str), \
Version.filter2(rad, str, thrL, thrH) \
)

function filter0 (clip c, int radius, float strength) {
Assert(radius < 32, "filter0: radius must be < 32")
return(MessageClip("0"))
}

function filter1 (clip c, int radius, float strength) {
Assert(radius < 32, "filter1: radius must be < 32")
return(MessageClip("1"))
}

function filter2 (clip c, int radius, float strength, int thrL, int thrH) {
Assert(radius < 16, "filter2: radius must be < 16")
return(MessageClip("2"))
}


Why is this?

Other than using other conditional constructs, or splitting variables so each function/filter has its own set which I would regard very messy, what other ways are there of getting around this issue?

Many thanks,
Francois

Gavino
29th November 2012, 21:36
The Select() function, although built-in to Avisynth, is not treated specially by the parser, so all its arguments are evaluated before it is called to make its actual choice.

On the other hand, the conditional test with '?' and ':' is a ternary operator built into the parser itself, so only evaluates the 'true' or 'false' branch as appropriate.

IanB
29th November 2012, 21:56
@Gavino, you're to quick :D

@fvisagie,

The ? : is implemented directly in the parser so only the one branch is evaluated at compile time....
AVSValue ExpConditional::Evaluate(IScriptEnvironment* env)
...
return (cond.AsBool() ? Then : Else)->Evaluate(env);
...
Select is an inbuilt function, the parser evaluates all the arguments before calling the function....
AVSValue Select(AVSValue args, void*, IScriptEnvironment* env)
{ int i = args[0].AsInt();
...
return args[1][i];
}
Consider this piece of script :-Function MySelect(Int i, Clip A, Clip B, Clip C) {
Return Select(i, A, B, C)
}

fvisagie
30th November 2012, 07:50
@IanB,

Great suggestion, not Select()ing functions. In my case it ended up as follows which works great.

Eval(Select(shrpnum, \
"""a.gaussianblur(varY=vshy, varC=vshc, y=ysh, u=ush, v=vsh).mt_lutxy(a, "y x - " + String(strsh) + " * y +", y=ysh, u=ush, v=vsh)""", \
"""a.unsharp (varY=vshy, varC=vshc, strength=strsh, y=ysh, u=ush, v=vsh)""", \
"""a.mt_lutxy (a.repair (a.repair (a.repair (a.repair (a.repair (a.repair (a.repair (a.repair (a.medianblur (rshy, rshc, rshc), 4), 4), 4), 4), 4), 4), 4), 4), "x x y - abs " + string (strsh, "%#.2f") + " 2 ^ / 1 " + string (strsh, "%#.2f") + " / ^ " + string (strsh, "%#.2f") + " 3 ^ * x y - x y - abs " + string (strsh, "%#.2f") + " + / * +", y=ysh, u=ush, v=vsh)""", \
"""a.TUnSharp(strength=Int(strsh), thresholdL=thL, thresholdU=thU, type=type, map=map, lim=lim, radius=rshy, gui=false)""" \
) \
)

You've been a great help, thanks guys.