0
$\begingroup$

In this question I asked a basic question about how to check argument types such that there was useful output from the front end when calling functions. Based on elements of the nice answer by @j-m-is-computerless I have developed the following, which works but is somewhat tedious in use.

First I give an example of the usage of the goodArgQ function which does type checking in the body of function definitions; the definitions of goodArgQ and its dependencies are at the end after the discussion and question.

ClearAll[columnsExistQ];
columnsExistQ::usage="Returns a list of True/False for each column if the named column exists in the current database in the specified table.";
columnsExistQ[conn_, tableName_, cols_]:=
    Module[{t, abortOnFail = True, debugPrint = True},
        goodArgQ[conn, "SQLConnection","abortOnFail"->abortOnFail, "debugPrint"->debugPrint];
        goodArgQ[tableName, StringQ, "abortOnFail"->abortOnFail, "debugPrint"->debugPrint];
        goodArgQ[cols,ListQ, "abortOnFail"->abortOnFail, "debugPrint"->debugPrint];
        goodArgQ[#,StringQ, "abortOnFail"->abortOnFail, "debugPrint"->debugPrint] & /@ cols;
        (* functional code here*)
    ]

The advantage to me of this type checking is that by appropriate use of the abortOnFail and debugPrint options I can focus on errors progressively.

However, what I would like to do is to develop a new front end syntax, similar to the following modification of the columnsExistsQ function

columnsExistsQ[conn As SQLCOnnection, tableName As String, cols As List of String]:=...

(where case of "As"", "of" should be ignored)

But I cannot work out how to get, let alone process, such an argument list.

Questions (For the sake of brevity I have kept the question very high level) How could one define such a way of defining functions so that the "as" etc. would automatically inline the appropriate goodArgQ calls - or e.g. use Map with a single additional function passed the arguments in list form.

How else might one compactly (i.e. avoiding the extra coding of @j-m-is-computerless and my own work) achieve the aim of declaring argument types such that MMA does not just silently do nothing if there is no match to a function definition?

Note this is the first time I have used any form of Hold, and I did try various Hold types and the like in order to get the argument list, alas to no avail.

The argument checking functions

ClearAll[goodArgQ]; (* clear all values, definitions, attributes, messages, and defaults *)
ClearAll[goodArgQByQ];
ClearAll[goodArgQbyHead];

Options[goodArgQ]={"abortOnFail"->True, "debugPrint"->False};
Options[goodArgQByQ]={"abortOnFail"->True, "debugPrint"->False};
Options[goodArgQbyHead]={"abortOnFail"->True,, "debugPrint"->False};

SetAttributes[goodArgQ, HoldFirst];
SetAttributes[goodArgQbyHead, HoldFirst];

goodArgQByQ::usage="Checks argument by Head with test value as string. Options: abortOnFail (Boolean), debugPrint (Boolean)";
goodArgQbyHead[paramName_, paramQ_, OptionsPattern[]]:=
    Module[{},
        If[ToString[Head[paramName]]!=paramQ,
            If[OptionValue["debugPrint"]==True, Print[Style[ToString[HoldForm[paramName]] <> " does not have required head " <> paramQ,Darker[Red]]]];If[OptionValue["abortOnFail"]==True, Abort[]];,
            If[OptionValue["debugPrint"]==True, Print[Style[ToString[HoldForm[paramName]] <> " has required head " <> paramQ,Darker[Green]]];];
        ];
    ];
goodArgQByQ::usage="Checks argument by Q function. Options: abortOnFail (Boolean), debugPrint (Boolean)";
goodArgQByQ[paramName_, paramQ_, OptionsPattern[]]:=
    Module[{},
        ReleaseHold[paramName];
        If[paramQ[paramName]==False, 
            If[OptionValue["debugPrint"]==True, Print[Style[ToString[paramName] <> " does not satisfy " <> ToString[paramQ] <> " = True",Darker[Red]]]];If[OptionValue["abortOnFail"]==True, Abort[]];,
            If[OptionValue["debugPrint"]==True, Print[Style[ToString[paramName] <> " satisfies " <> ToString[paramQ] <> " = True",Darker[Green]]];];
        ]
    ];

goodArgQ::usage="Checks argument by Q function or Head with test value as string. Options: abortOnFail (Boolean), debugPrint (Boolean)";
goodArgQ[paramName_, paramQ_, OptionsPattern[]]:=
    Module[{},
        If[Head[paramQ]== String,
            goodArgQbyHead[paramName,paramQ, "abortOnFail" -> OptionValue["abortOnFail"],"debugPrint" -> OptionValue["debugPrint"]];Return[]]; 
        goodArgQByQ[paramName, paramQ, "abortOnFail" -> OptionValue["abortOnFail"],"debugPrint" -> OptionValue["debugPrint"]];
    ];
$\endgroup$
  • $\begingroup$ Are you looking for any alternative for easier catching of what exactly fails or do you want to enforce a specific behavior but are struggling with implementation? $\endgroup$ – Kuba Nov 2 '18 at 12:00
  • $\begingroup$ @Kuba primarily any concise way to control declaration and catching, but even if not used I would now like to know for educational purposes whether/how I might I might get and parse the new-form declaration syntax... IF it's not too abstruse/time consuming for someone to answer & that part of the answer would be for info only. I did wonder whether your templating system could assist (now that I am using it "out of the box") but it seems non-trivial $\endgroup$ – Julian Moore Nov 2 '18 at 12:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.