I have understood and do see your points, Quentin. And I very much appreciate your perspective and insights.
But in several details, we will simply disagree.
1 - DATA STEP and %SYSFUNC macro (text-generation) world are different, and have their own sets of rules.
In DATA STEP, a blank CHAR has length 1.
In macro world, a blank string has %length 0. This fundamental disconnect definitely contributes to SAS' inconsistencies.
%SYSFUNC() should bring DATA STEP functions into the macro (text-gen) world. To me, this means that %SYSFUNC() should translate the DATA STEP blank-char concept into a zero-length NULL STRING.
This has been and remains my main point: %SYSFUNC() fails to do this most fundamental translation into the macro (text-gen) world consistently - OK for multiple arguments; ERROR for single arguments. I see no explanation for this (details follow).
2 - %SYSFUNC() apparently demands a comma to delimit arguments. It does not recognize the open/close parens as delimiting a single argument. This to me is a design failure, and I struggle to alter that assessment.
See this documentation: "All arguments in SAS language functions within %SYSFUNC must be separated by commas."
That's the fundamental design flaw. How in the world are you supposed to separate a single argument with a comma?! Not possible - so design oversight.
The open/close parens of the function call should be sufficient to delimit a single argument, including the NULL argument, which otherwise works fine for 2+ NULL arguments.
%SYSFUNC()'s focus on the comma has blinded it to the open/close delimiters.
NULL arguments are fine in the macro (text-gen) world. %SYSFUNC() simply does not make the translation from DATA STEP to Macro world, and I think this stems from the open/close-parens-as-delimiters issue.
Yes, I expect that we will disagree on this point 🙂
( I have no issue with TRANWRD() and TRANSTRN() - function documentation clearly states when blank (null) arguments are valid - or not. )
3 - By comparison, I do consider STRIP() flawed and inconsistent with the macro world.
Taking your example, I see no difference between a NULL STRING (str=), and an EXPLICIT NULL STRING (str=%str()).
Both arguments are NULL STRINGS - strings with length zero.
The EXPLICIT NULL STRING simply helps %SYSFUNC() get over its fundamental failure to recognize a NULL STRING simply based on the open/close-paren delimiters:
%macro test_null_string_handling(str=);
%put >>%sysfunc(STRIP(&str))<< ;
%mend test_null_string_handling;
%test_null_string_handling
%*;
%test_null_string_handling(str=%str()) /* <== NULL STRING ASSIST, to overcome %SYSFUNC() design flaw */
%*;
With the assist, despite any macro-quoting tokens/symbols, the DATA STEP function STRIP() nonetheless receives a NULL STRING.
The results - the assist of %str() eases %SYSFUNC() over its design flaw:
323 %test_null_string_handling
324 %*;
ERROR: The function STRIP referenced by the %SYSFUNC or %QSYSFUNC macro function has too few arguments.
>><<
325 %test_null_string_handling(str=%str()) /* <== NULL STRING ASSIST, to overcome %SYSFUNC() design flaw */
>><<
326 %*;
4 - %SYSFUNC() simply cannot recognize otherwise valid single-null-string-arguments.
That's a %SYSFUNC() design flaw.
Yes, I expect that we will disagree on this point, as well 🙂
This has been a very helpful, and at times very frustrating thread for me. I thank all who have contributed. Such frustration, for me, is a mark of insight and learning. This is what you have all given to me.
Thank you!
... View more