Validating arguments in CoffeeScript? - coffeescript

I have a function with a bunch of arguments, and I just want to check if any of them are falsy (empty, undefined, null, etc.).
One option is obvious to just check every argument individually, but it's pretty repetitive:
if not arg1
response.send 400, 'Missing argument arg1'
if not arg2
response.send 400, 'Missing argument arg2'
I can simplify that a bit with this, but I still have to list out every every argument and argument name:
for key, value of { 'arg1': arg1, 'arg2': arg2 }
if not value
response.send 400, "Missing argument #{key}"
I was hoping to do something like this:
for key, value of arguments
if not value
response.send 400, "Missing argument #{key}"
But arguments is more like an array. Is there a way to get the arguments as an object, or get the argument names as an array? Am I going about this this wrong way?
What is a good way of validating a bunch of arguments without repeating myself?

You could write an check function that parses the parameter names from the string representation of your function (there is really no other way)
check = ()->
f = "" + arguments.callee.caller
r = /function \((.*)\)/
regres = r.exec(f)
pnames = regres[1].split(",")
params = (pn.trim() for pn in pnames)
for index in [0...arguments.length]
if arguments[index] == null || arguments[index] == undefined
console.log "argument: #{params[index]} is null"
handleRequest = (x, y, z)->
#give all your params in the correct order to the check function
check(x, y, z)
handleRequest(1, 2, "lala")
handleRequest(1, 2)
Now the fact that this is somehow possible shouldn't mean that you should do it. This solution is at best brittle and will create confusion if you change parameter position. Some would probably claim its evil - me included ;-)
I'd rather advise you that you change your API design.
From your response.send I would assume that you are in an web environment? Why dont you simply use the params hash that the framework you are using is handling to you? Most frameworks will do exactly this.
Another possibility would be to define default values for your parameter so that received parameters are always well defined?
handleRequest = (x, y = "somevalue", z = "anothervalue")->

I believe there is no clear way of achieving what you want, but a nasty way of doing this (based on similar threads for javascript, like this and this), which may be error prone, is to parse the function itself, get the names of the arguments and make them an array:
fn = (a,b,c,d,e,f) ->
fns = fn.toString()
args = fns.slice(fns.indexOf('(')+1, fns.indexOf(')')).split(', ')
for idx in [0...args.length]
console.log 400, "Missing argument #{args[idx]}" unless arguments[idx]
fn('', null, 'arg1', undefined, 'arg2')
#Output:
#400 'Missing argument a'
#400 'Missing argument b'
#400 'Missing argument d'
#400 'Missing argument f'

Related

error: "struct" expression not at top level

function check(str,arg;type=DataType,max=nothing,min=nothing,description="")
#argcheck typeof(arg)==type
#argcheck arg>min
#argcheck arg<max
#argcheck typeof(description)==String
return arg
end
function constr(name,arg,field)
return :(function $name($arg,$field)
new(check($name,$arg,$field))
end)
end
macro creatStruct(name,arg)
code = Base.remove_linenums!(quote
struct $name
end
end)
print(arg)
append!(code.args[1].args[3].args,[constr(name,arg.args[1].args[1],arg.args[1].args[2])])
code
end
macro myStruct(name,arg)
#creatStruct name arg
end
#myStruct test12 (
(arg1,(max=10))
)
In my code above I'm trying to build a macro that Creates a struct, and within the struct, you can define an argument with boundaries (max, min) and description, etc.
I'm getting this error:
syntax: "#141#max = 10" is not a valid function argument name
and every time I'm trying to solve it, I get another error like:
LoadError: syntax: "struct" expression not at top level
So, I think my Code/Approach is not that cohesive. Anybody can suggest tips and/or another Approche.
You're attempting to make an argument name max with a default value of 10. The error is about max=10 not being a valid name (Symbol), while max is. The bigger issue is you're trying to put this in the struct expression instead of a constructor method:
struct Foo
bar::Float64
max::Int64
end
# constructor
Foo(bar, max=10) = Foo(bar, max)
So you have to figure out how to make an expression for a method with default values, too.
Your second error means that structs must be defined in the top-level. "Top-level" is like global scope but stricter in some contexts; I don't know the exact difference, but it definitely excludes local scopes (macro, function, etc). It looks like the issue is the expression returned by creatStruct being evaluated as code in myStruct, but the LoadError I'm getting has a different message. In any case, the error goes away if I make sure things stay as expressions:
macro myStruct(name,arg)
:(#creatStruct $name $arg)
end

How to pass Optional-Positional arguments to a function in matlab

I am trying to understand the usage of positional arguments in MATLAB and I was referring to this page.
Let's say I have a MATLAB function defined as follows:
function printPhoto(filename,varargin)
p = inputParser;
defaultFinish = 'glossy';
validFinishes = {'glossy','matte', 'colorful'};
checkFinish = #(x) any(validatestring(x,validFinishes));
defaultColor = 'RGB';
validColors = {'RGB','CMYK','colorful'};
checkColor = #(x) any(validatestring(x,validColors));
defaultWidth = 6;
defaultHeight = 4;
addRequired(p,'filename',#ischar);
addOptional(p,'finish',defaultFinish,checkFinish);
addOptional(p,'color',defaultColor,checkColor);
addParameter(p,'width',defaultWidth,#isnumeric);
addParameter(p,'height',defaultHeight,#isnumeric);
parse(p,filename,varargin{:});
end
When I call the above function as follows: printphoto('myFile.img', 'colorful'), is it possible to make this second argument to correspond to the second optional positional argument in the function definition i.e. color='colorful' and not finish='colorful'?
This is what you get when mixing optional-positional arguments and parameters. IMHO, you should use one or the other, but not both.
When you define an argument as positional, you're telling MATLAB that this input will always appear in that specific place, if it does appear. If you want to play around with the order of the inputs, that's exactly what a parameter-type argument is for.
Just think about it, the following syntaxes aren't that different:
printphoto('myFile.img','color','colorful')
printphoto('myFile.img', color='colorful' )
So I would suggest sticking with parameter-type arguments, but if you insist on having them positional, make sure that you assign a default value to the input if the user wants to "skip" it (by supplying some agreed-upon "null" value such as "" or []).

Does mathjs have any concept of null or undefined?

I think the answer is probably 'no' as from what I can tell maths libraries don't seem to handle null, but what I'd like to have is to be handle null in these scenarios:
x=1
(y not defined)
z = sum(x, y)
with eval() ideally giving:
z=1
However, this throws an exception, as y is not defined.
In effect I'm defaulting 'y' to zero in that example, and that won't work in all scenarios.
So, what I suppose I'm asking is, is there an in-built way to define a default for a variable if it's not assigned a value?
If not, I'm assuming that this would be possible by writing a custom function. If someone could confirm this, I'd really appreciate it.
Thanks :-).
Ok - I was looking through the release notes for v4 and saw it talking about the constants 'null, undefined' (and others). So, in order to solve this I have to define a variable as undefined (probably should have known this!).
(Note: I suspect these constants are available in previous version too.)
Then combined with a 'default' custom function I can get what I wanted:
x=1
y = null
z = sum(x, def(y, 0))
z=1
where 'def' is defined and imported as below (making use of 'lodash'):
var customFunctions = {
def: function (value, defaultValue) {
return !_.isNil(value) ? value : defaultValue;
}
};
math.import(customFunctions);
BOSH!

Is there a way to use matlabs inputparser to use the default value when non valid data is entered?

So I am trying to add an input parser to a few files in matlab. All of the parameters have a default value and for this specific case there has to be 2 optional positional parameters and then the rest are truly optional. This is the code that I have for the input parser that does correctly validate the input but I need something that if I pass an empty string or a null in the parser would just use the default option. What would be the "best" way of going about this?
p = inputParser;
validStrings = {'one', 'two', 'three'};
defaultString = 'none';
checkString = #(x) (any(validatestring(x,validStrings));
addOptional(p,'number',defaultString, #checkString);
when passing an empty string into this it just errors out saying that '' is not an expected option.

Does MATLAB lets you assign default value for input arguments for a function like python does?

I am working on a project and have many functions to create and they do need lots of debugging so instead of just hitting the run button i have to go to command window and give a function call.
does MATLAB support assignment of default values to input arguments like python does?
In python
def some_fcn(arg1 = a, arg2 = b)
% THE CODE
if you now call it without passing the arguments it doesn't give errors but if you try the same in MATLAB it gives an error.
For assigning default values, one might find it easier to manage if you use exist function instead of nargin.
function f(arg1, arg2, arg3)
if ~exist('arg2', 'var')
arg2 = arg2Default;
end
The advantage is that if you change the order of arguments, you don't need to update this part of the code, but when you use nargin you have to start counting and updating numbers.
If you are writing a complex function that requires validation of inputs, default argument values, key-value pairs, passing options as structs etc., you could use the inputParser object. This solution is probably overkill for simple functions, but you might keep it in mind for your monster-function that solves equations, plots results and brings you coffee. It resembles a bit the things you can do with python's argparse module.
You configure an inputParser like so:
>> p = inputParser();
>> p.addRequired('x', #isfinite) % validation function
>> p.addOptional('y', 123) % default value
>> p.addParamValue('label', 'default') % default value
Inside a function, you would typically call it with p.parse(varargin{:}) and look for your parameters in p.Results. Some quick demonstration on the command line:
>> p.parse(44); disp(p.Results)
label: 'default'
x: 44
y: 123
>> p.parse()
Not enough input arguments.
>> p.parse(Inf)
Argument 'x' failed validation isfinite.
>> p.parse(44, 55); disp(p.Results)
label: 'default'
x: 44
y: 55
>> p.parse(13, 'label', 'hello'); disp(p.Results)
label: 'hello'
x: 13
y: 123
>> p.parse(88, 13, 'option', 12)
Argument 'option' did not match any valid parameter of the parser.
You can kind of do this with nargin
function out = some_fcn(arg1, arg2)
switch nargin
case 0
arg1 = a;
arg2 = b;
%//etc
end
but where are a and b coming from? Are they dynamically assigned? Because that effects the validity of this solution
After a few seconds of googling I found that as is often the case, Loren Shure has already solved this problem for us. In this article she outlines exactly my method above, why it is ugly and bad and how to do better.
You can use nargin in your function code to detect when no arguments are passed, and assign default values or do whatever you want in that case.
MathWorks has a new solution for this in R2019b, namely, the arguments block. There are a few rules for the arguments block, naturally, so I would encourage you to learn more by viewing the Function Argument Validation help page. Here is a quick example:
function ret = someFunction( x, y )
%SOMEFUNCTION Calculates some stuff.
arguments
x (1, :) double {mustBePositive}
y (2, 3) logical = true(2, 3)
end
% ...stuff is done, ret is defined, etc.
end
Wrapped into this is narginchk, inputParser, validateattributes, varargin, etc. It can be very convenient. Regarding default values, they are very simply defined as those arguments that equal something. In the example above, x isn't given an assignment, whereas y = true(2, 3) if no value is given when the function is called. If you wanted x to also have a default value, you could change it to, say, x (1, :) double {mustBePositive} = 0.5 * ones(1, 4).
There is a more in-depth answer at How to deal with name/value pairs of function arguments in MATLAB
that hopefully can spare you some headache in getting acquainted with the new functionality.