## Various suggestions sent to SAS Institute

5002/24/2005 - Enhancing SAS objects within _Windows_ Explorer

There are some situations when I find myself having to look at dozens of SAS catalogs in a myriad of folders. The catalogs are either copies and backups, or variants of forgotten, abandoned or delayed code development.

I would find great utility in _Windows_ explorer, if a mouse hover over a .sas7bcat file would present a list of catalog entries.

The effect would be similar to that of WinZip showing the list of files zipped or Office show the document properties (author, date, etc...). I think this programming topic is ShellExtensions.

Even greater utility would be to surface SAS catalog entries to the OS shell similar to how Windows XP Explorer can present a zipfile asif it were a regular folder. [New] For example: All the entries such as SCL, SOURCE, OUTPUT, LOG, FORM could be accessible to (at least in a read-only fashion) and integrated with Windows explorer (items and content could be found via Search dialog)

Thanks for listening.

4902/22/2005 - Metadata of compiled macros

Is there a way to programmatically determine the parameters of a compiled macro?

For example, suppose these two macros have been compiled.

%macro this(foo,bar,memo=);
%mend;

%macro that(data=,var=,limit=1000);
%mend;


I would be looking for some metadata table having this information

LibnameMemnameMacroPositionNameTypeDefault
worksasmacrthis1foo P.
worksasmacrthis2bar P.
worksasmacrthis3memo K.
worksasmacrthat1data K.
worksasmacrthat2var K.
worksasmacrthat3limitK1000

type: P (positional) or K (keyword)
default: would be truncated in the highly unlikely case of a default being >32K characters long.

This metadata table is somewhat similar to DICTIONARY.COLUMNS

4802/09/2005 - Request for new Descriptive Statistics function

The functions ORDINAL, SMALLEST, LARGEST and PCTL all deal with aspects of a set of values when ordered.

Consider ORDINAL.
ORDINAL returns the k'th smallest value of a set.

value = ORDINAL (k, list of values)


The function I would like to see is the inverse.

k = INDEXOF (value, list of values);


if value < smallest value then k=0
if value > largest value then k=#of values in list + 1
else k = kth smallest value that is >= value

When non-equality (i.e. v[k] < value < v[k+1], the SYSRC would be set to an appropriate indication value.

In essence
sort values
do k = 1 to dim(values) while (value < values[k]); end;

INDEXOF might also be called RANKOF, POSITION, LOCATION, ORDINALINDEX, ORDINALRANK or ABSRANK.

The term rank has synonymity with the strings RANK function. INDEX has been claimed by the string functions and probably shouldn't be overloaded.

4701/23/2005 - Enhanced Editor suggestion

I have my comments colored with a non-white background. The application of the comment color could be tweaked in this way

Suppose there is a comment block

/*
*
*
*/

or
     /*
This is a
comment
*/


At present only the /* ... */ area is colored as comment.

I would prefer the color as such:
- if only space precedes the start of the comment, color that the same as a comment as well.
- if only space follows the end of the comment, and the entire prior line was comment colored, then color from end of comment to end of line as if it were a comment.

The same would apply to multiline comment statements

  *
* This is a comment
* ;

data ...


I would prefer three _entire_ lines colored as a comment.

4601/22/2005 - Suggestion for new command similar to POSTMESSAGE.

The POSTMESSAGE command displays a dialog with an OK button.

I recommend the development of a POSTDIALOG command for displaying a message and accepting input.

There would be two modes of use:

Mode 1.
POSTDIALOG "string" macro-var
A single text entry is create after the string. The value of the macro var appears in the text entry. An OK and CANCEL button are in the dialog. Edits to the text entry become the new value of the macro-var if the OK button is clicked.

Mode 2.
POSTDIALOG window-name
Look for a previously defined macro window created with the %WINDOW statement. If it exists, render the window using the look and feel of a system dialog (i.e. same look as POSTMESSAGE), instead of the look and feel of a DMS text window. The dialog window would populate macro variables (upon OK) in the same manner as %DISPLAY.

Here is another interesting idea. Suppose I wanted to process an HTML form submission from within the DMS session.

POSTHTML "html-file"
Through some creative arrangement and configuration of applicable technology, the html file is displayed using the DMS clients default browser, and the submit button of the form would return the form parameters back to the DMS session (similar to how SAS/Intrnet delivers form values in macro variables) in macro variables. If working within the confines of Internet Explorer, you could create a special program, display.exe, that is part of SAS installation. display.exe would the "Microsoft Web Browser" control to supervise all the clicks and such and make sure the values get back to the SAS DMS session.

4510/08/2004 - New Base Routines ALLPERK, ALLCOMB, RANCOMB

There are routines ALLPERM, RANPERM and RANPERK

A new ALLPERK routine would be beneficial in some scenarios

ALLPERK (k, var1,...varN)


ALLPERK would iterate each combination of K items permutations.

I.e.
There are COMB(N,K) groups of K things taken N at a time, and each group has K! permutations.

In a similar vein, ALLCOMB could iterate all the combinations of N,K. RANCOMB would be the random version.

* Example ;

array L [6] ('a', 'b', 'c', 'd', 'e', 'f');
do i = 1 to comb(6,3);
call ALLCOMB (i, 3, of L1-L6);
put L1-L3;
end;

might show this

a b c
a b d
a b e
a b f

a c d
a c e
a c f

a d e
a d f

a e f

b c d
b c e
b c f

b d e
b d f

b e f

c d e
c d f

c e f

d e f

4407/27/2004 - New SQL Dictionary table - WINDOWS

More aspects of the DMS environment could be made available to developers and programmers.

Consider a new dictionary table DICTIONARY.WINDOWS or SASHELP.VWINDOW. This table would have at least one column "TITLE" which would correspond to each window that would be accessible via the NEXT "window-title" command. Thus there would be one row per window that one could theoretically Ctrl-Tab to.

4306/10/2004 - Temporary Arrays

The DATA Step statement

array dash[*] _temporary_ (1,2,3,4,5,6,7,8,9,10);

Causes

ERROR: The non-variable based array dash has been defined with zero
elements.

I think it would be helpful if the array declaration grammar accepted

[*] _temporary_ (<initialization>)

to mean the number of elements in the initialization, N, is automatically
the size of the array.


[*] is really [1:*]

[<lower-bound>:*] should be accepted, automatically setting upper-bound to lower-bound + N - 1
Likewise,
[*:<upper-bound>] should automatically set the lower-bound to upper-bound-N+1

4203/08/2004 - Proc EXPORT
A recent thread on SAS-L originated this idea.

Proc EXPORT ...
DBMS=EXCEL
...
;

can be improved by allowing character values that represent excel formulas
be transferred as formulas instead of being blindly quoted.

For example, suppose we have

data foo;
sum = '=sum(1,2,3)';
run;

proc export data=foo outfile='c:\temp\sum.xls' dbms=excel;
run;

creates an xls file with a cell that shows
=sum(1,2,3)
Upon closer examination with F2 the cell value is seen to be
'=sum(1,2,3)

This indicates Proc EXPORT blindly quotes sas character values being moved
into excel.  This makes sense when protecting innocent users, but the more
sophisticated would like an option to allow values starting with = to be
transferred 'as-is'

A simple option value modifier would do it.  I would be happy with either of
these:
Formulas=Yes
DBMS=Excel/Formulas

You could even throw in a
VAR varname / STYLE=....;
to allow us to set column specific formatting ala ODS.

4102/19/2004 - Hash object dataset: data: and .add()
To: <Base.Research@sas.com>

Here is the suggestion:

When dataset: option is specified, allow data items that are not columns,
but do provide a warning.

This would come in handy when a hash data item is to be computed and
associated with each key.  The initial value of such data items would be
missing.

<TANGENT>
This brings up two other related suggestions:

1. data item default values
The default defaultValue would be plain missing. Sample syntax:

defineData('var0', 'var1/defaultValue=.X', 'var2/defaultValue=-1)

.add(key:, data:, data:) method invocations where the number of data items
is less than the number specified in .defineData() would have the unnamed
data items set to their initial value, which can be specified in
defineData().

* 2nd and 3rd data items default to .X and -1;
</TANGENT>

The inability to do so today can be worked around by setting up a second hash that
contains the same keys as the first hash, and whose data items are the
computed values.

In this example it is desired to get forward and backward linkages
associated with each key, when the initial data contains only the backward

data transactions;
do id = 1 to 10;
pid = id - 1;
output;
end;
run;

data _null_;
declare hash H (dataset:'transactions');
H.defineKey ('id');
H.defineData ('id', 'pid', 'nid');
H.defineDone ();
call missing (id, pid, nid);
run;
/*
fails because nid is not a column of transactions;
ERROR: Variable nid is not on file WORK.TRANSACTIONS.
ERROR: Hash data set load failed at line 941 column 3.
ERROR: DATA STEP Component Object failure. Aborted during the EXECUTION phase
*/

* work around, two hashes;
data _null_;
declare hash H (dataset:'transactions', ordered:'A');
H.defineKey ('id');
H.defineData ('pid', 'id');
H.defineDone ();

declare hash HNEXT (ordered:'A');
HNEXT.defineKey ('id');
HNEXT.defineData ('id', 'nid');
HNEXT.defineDone ();

call missing (id, pid, nid);

declare hiter HI ('H');
do rc = HI.first() by 0 while (rc=0);
put id= pid=;

nid = id;
id = pid;

rc = HI.next();
end;

put;

declare hiter HI2 ('HNEXT');
do rc = HI2.first() by 0 while (rc=0);
put id= nid=;
rc = HI2.next();
end;
run;

4002/07/2004 - Hash object introspection
To: <Base.Research@sas.com>

I look forward to using hashes in version 9.1.

Is there a way to query a hash object as to what variables are the keys and
datas ?

Consider this stub that shows the hash in the log:

declare hash h_foo();
h_foo.defineKey('<key-1>', ..., '<key-N>');
h_foo.defineData('<data-1>', ..., '<data-M>');
h_foo.defineDone ();

... stuff that populates the hash ...

declare hiter hi('h_foo');
do rc = hi.first() by 0 while (rc = 0);
put <key-1>= ... <key-N>= <data-1>= ... <data-M>=;
rc = hi.next();
end;
hi.delete();

Now consider trying to write a macro that does the same:

%macro hashDump (h);
declare hiter hi ("&h");
do rc = hi.first() by 0 while (rc = 0);
do i = 1 to &h..getNumberOfKeyVariables();
varname = &h..getKeyVarName(i);
varvalue = vvaluex (varname);
put varname "=" varvalue;
end;
do i = 1 to &h..getNumberOfDataVariables();
varname = &h..getDataVarName(i);
varvalue = vvaluex (varname);
put varname "=" varvalue;
end;
rc = hi.next();
end;
hi.delete();
%mend;

This would only work if the hash object was updated to include methods
getNumberOfKeyVariables()
getNumberOfDataVariables()
getKeyVarName(int i)
getDataVarName(int i)

Lastly, a hash is certainly an in memory data store.
Would it be possible to utilize a hash as a input stream accessible via SET statement?

In terms of OO it would mean any DATA Step component object that satisfies
the requirement of having an interface named SET could somehow be utilized in a SET
statement.
i.e.
libname hash 'h_foo' engine=HashSetInterface;
data _null_;
declare hash h_foo;
...
h_foo.defineDone();
set hash.h_foo;

I can't think of a scenario right now where this would be applicable,
but it would allow someone to merge a hash with a table.

If new component objects are to be developed, I would be interested in
either AF objects or (in windows) objects that operate very much like
objects hosted in the wsh environment.


A birdie wrote back:
 I've made a note to look at these for 9.2.  Providing the
'reflection' methods

getNumberOfKeyVariables()
getNumberOfDataVariables()
getKeyVarName(int i)
getDataVarName(int i)

probably isn't too hard.

3901/09/2004 - New graphics statement, NAME

A single Proc GSLIDE step can output multiple grsegs when it contains several run groups.

proc gslide gout=foo;
goptions reset=note;
note 'foo';
run;
goptions reset=note;
note 'bar';
run;


This creates two grsegs named gslide and gslide1.

If I add a /name="mine" to the proc statement then the grsegs are named mine and mine1.

Suppose I want to give my slides the names foo and bar.
The only way to do that now is to run GSLIDE twice, or use GREPLAY or CATALOG to rename the entries.

The suggestion is to implement a new graphics statement:

NAME "name", or perhaps
NAMEBASE "name"

When this statement is encountered in a run group of a graphics procedure, it changes the current output name to the specified name. (Presently the current name is either a Proc selected default (such as GSLIDEn) or NAME.n based on the NAME= value of the proc statement.

3809/27/2003 - DATA Step, rxmatch and hash object

The version 9 hash component and perl regular expression in DATA Step are godsends (well pretty darn close). An awesome improvement would be to couple the two so that rxmatch() could populate a hash from named sub-expression groupings.

I speculate a superior way would be to expose or promote rxpattern tag expression variables to host variables in DATA Step PDV.

Example (with SAS regex):

data _null_;
string = '1001: ABC 123 DEF 456';

length key first second third fourth $15; declare hash hh; hh.addkey ('key'); hh.adddata ('first'); hh.adddata ('second'); hh.adddata ('third'); hh.adddata ('fourth'); rx = rxparse ('key=<^w+> ":"$w+ first=<^w+> $w+ second=<^w+>$w+
third=<^w+> $w+ fourth=<^w+>'); rc = rxmatch (rx, string, 'PROMOTE'); * DATA step PDV vars & values; * key '1001' * first 'ABC' * second '123' * third 'DEF' * fourth '456' *; hh.add (); run;  and lo and behold a birdie chirps back Hello Richard, I wanted to let you know that coupling of the regular expressions and hash objects is already in the works. Regards, xxxxxxxx 3708/06/2003 - BASE: Allow SUBSTR to accept negative valued arguments It would be beneficial to allow negative arguments in the SUBSTR() function. This discussion is for left to right languages.  SUBSTR ( string, position, length )  if position is negative then starting point of the extraction is length(string) + position if length is negative, then resolved position is the _ending_ position of the extraction substr ( 'ABC123', 3, 3 ) -> 'C12' substr ( 'ABC123', -3, 3 ) -> '123' substr ( 'ABC123', 3, -3 ) -> 'ABC' substr ( 'ABC123', -3, -3 ) -> 'BC1'  Since SUBSTR is so embedded and allowing negative args might conflict certain systems that rely on error detecting such, an alternative might be to have a new function such as SUBSTRX() or SUBSTRING() 3607/30/2003 - SAS Explorer Commands After a recent discussion with a colleague of mine, I respectfully submit that the SAS explorer system could be better 'scripted' if some addtional commands were recognized. from help (a000403312): ----- Explorer commands You can use the following commands in the Explorer window to perform actions. These actions are also available from the menus and toolbox: DETAILS toggles the Details view on and off. LARGEVIEW changes the view to large icons on some operating systems. SMALLVIEW changes the view to small icons on some operating systems. NEWOBJ allows you to create a new item in the active folder. For example, when a library folder is selected, NEWOBJ allows you to create a new library member. LIBASSIGN opens the New Library window. UPLEVEL moves up one level in the folder hierarchy. TREE toggles the folder list (or treeview) on and off. SELECT_ALL selects all items in the listview. DESELECT_ALL deselects all selected items. REFRESH refreshes the window contents COPYITEM copies the specified item from one library or catalog to another. DELETEITEM deletes the specified item. MOVEITEM moves the specified item from one library or catalog to another. RENAMEITEM renames the specified item. -----  1. Document that CHILD toggles list view on and off. 2. Implement SELECT value value could be 'single valued' or a 'wildcard'. Regardless, after this command, some items in the list view would be selected (if their names match). An advanced version of select would be SELECT expression involving list view column namess e.g., When the listview is showing the contents of a catalog SELECT type = 'Pmenu' and name like 'foo%' 3. Implement OPENITEM If the selected item supports the Open menu choice, do it. If open means opening a child of a node and changing the list view, do that. If it means performing the open action of a catalog entry (i.e., build, notepad, gsubmit...), do that. 4. Update the DMSEXP command to handle the same arguments handled by EXPLORER 3510/17/2002 - Data step compiler and CONSTANT() function. The Data Step compiler could do a better job when it has to deal with the CONSTANT() function. The following example demonstrates to me that assignment of CONSTANT('PI') is not being optimized. 76 data _null_; 77 pi = constant ('PI'); 78 do p = 1 to 1e8; 79 pi = pi; 80 end; 81 stop; 82 run; NOTE: DATA statement used: real time 2.42 seconds cpu time 2.39 seconds 83 84 data _null_; 85 pi = constant ('PI'); 86 do p = 1 to 1e8; 87 pi = constant ('PI'); 88 end; 89 stop; 90 run; NOTE: DATA statement used: real time 9.10 seconds cpu time 8.97 seconds  It appears to me the function call is being performed each time in the loop. I would have expected the compiler to inline the result of CONSTANT('PI') since the argument to the function is itself a constant and can not change. 3409/27/2002 - [ BASE ] REORDER Statement or Data Set option A data set option to reorder the columns of data set specified during data set reading or writing (e.g. DATA= OUT= SET MERGE UPDATE DATA) would be helpful. Especially in cases when the data is being viewed, examined, reported or printed (or any other situation where varnum order of variables is implicitly dealt with). I suspect a Data Set option named something like REORDER= is appropriate. Set myData ( REORDER = id1-id3 measure1-measure3 unit1-unit3 ) FSVIEW MYLIB.WIDEDATA (keep=A: B: C: reorder=B: A: C9 C:)  Any unlisted variables would retain their original order after the listed variables. Variable name prefix operator would be honored e.g. MEASURE: Variable array operator would be honored e.g. MEASUREMENT_UNITS MEASURE8 MEASURE1-MEASURE7 If a Variable is 'up for consideration' more than once, it is placed in the first specified location. The concept could be extended to Proc and Data Steps with a new general statement REORDER ... ... ... ; similar to VAR, FORMAT, etc... Perhaps the keyword COLORDER or COLUMNORDER is more appropriate than REORDER. 3309/26/2002 - SCL List Function NamedItem() >The NamedItem() function could be improved by adding an argument that returns >the item type. At present, only the item position is returned, and the >ItemType() function is needed to determine the type of item at that position.  I just wanted to let you know that we received your suggestion and that it has been entered. Thanks for the great idea! :) 3207/14/2002 - SAS/AF Build mode An improvement to the SAS/AF build gui could be this. Presently: I can right click on an object to see a context menu. One of the choices is Properties, which brings up the object in the Properties Editor. Improvement: If the object right clicked on is a viewer with a model attribute already set, add this additional selection to the context menu: "Model Properties" This selection would bring up the Properties Editor with viewers model object active. 3107/11/2002 - Base SAS / Viewtable I have found that the table management/exploration interface found in the PL/SQL product of http://www.allroundautomations.com to be impressively concise and complete. I would recommend a close study of it's features for applicable use in future SAS versions, perhaps in an enhanced version of ViewTable called ManageTable. One of the neatest features I found was a third editing form to complement TABLEVIEW and RECORDVIEW. I call it VECTORVIEW, in which the column names are the rows and the column(s) (one or more) are records. I find this form of data presentation very useful when a table has many long text columns (which is annoying when in TABLEVIEW form) 3007/08/2002 - Base Timer A user could diagnose and/or profile a SAS program if there was a new command TIMER or function TIMER() TIMER<N> START TIMER<N> SPLIT TIMER<N> RESET TIMER<N> STOP t = TIMER ('START', <N>) ; returns 0 t = TIMER ('SPLIT', <N>) ; returns current elapsed time t = TIMER ('RESTART', <N>) ; returns current elapsed time and starts over t = TIMER ('STOP', <N>); returns current elapsed time and stops  2904/22/2002 - Enhanced Editor, Save As HTML I can use the File/Save As... menu to save my SAS program (which is wonderfully syntax highlighted) as an .html file. However, the saved file is simply an ASCII text file. The Save As HTML choice should instead write an HTML file that retains the syntax highlighting when viewed in a browser. The editor has all the necessary information and the file created would follow this simple template: • A STYLE type=text/css section to define colors and other display attributes • The BODY which contains a single PRE block. Within the PRE block any syntax highlight would be put in a SPAN block with the CLASS= set to match an element of syntax highlighting. Having this capability would ease dramatically the pains of creating tutorial and help web pages containing syntax highlighted SAS code. 2809/08/2001 - Base: ALIAS Improvements to SAS in version 8 include long column names. The improvement has lead to having long (or very long) column names in the Data Set for self documenting purposes. However, within a data or proc step, the use of a shorter, more manageable column name is more desirable when the focus of the program is local to an experts terminology. It would be a sort of temporary rename during the duration of the step. The real strength of ALIAS is that a column could be addressed with two different names. This could be a real help when trying to shoehorn some new data into an old program. i.e. two columns of a table might be X_AT_THE_TIME_WHEN_OBSERVED Y_AT_THE_TIME_WHEN_OBSERVED and an expert would just think in terms of X and Y. Using an ALIAS concept would allow this type of programming to occur. e.g. data ABC_2; set ABC; alias X_AT_THE_TIME_WHEN_OBSERVED = X; alias Y_AT_THE_TIME_WHEN_OBSERVED = Y; xPlusY = X + Y; run;  2708/17/2001 - Proc GSLIDE The GSLIDE procedure could be improved in the following way: Allow a DATA= option to be indicated. If that is done, then BY group processing, along with TITLE or (FOOTNOTE) statements containing #byval[n] or #byvar[n] substitution options can be used to generate multiple background slides. Those slides would be replayed later with other charts using GREPLAY. Consider a report in which 20 different background slides are necessary. Using a dataset to and GSLIDE would be prefered over GLIDE and 20 run; blocks or a macro that invoked GSLIDE 20 times. 2608/10/2001 - LOG2 window The SAS display manager environment could be improved in the following way: Provide a LOG2 window that contains only WARNINGS and ERRORS. When a row in LOG2 is clicked or double-clicked, the LOG window opens and positions itself to the appropriate row. Why is this useful ? Many programs can run into thousands if not tens of thousands of lines of code. When developing new code or modifying production code, changes can cause an error or warning that is easily overlooked. This is especially true when the log window autoscroll set to 0 to allow the fastest possible logging. If a LOG2 window existed, showing only the most critical of situations, fewer problems would go undetected. Alternatively, the LOG2 window could be designed to allow the user to specify one or more regular expression match strings that are automatically applied within the logging system. Thus, the LOG2 window could supply a user specific focus on ERROR:, WARNING:, NOTE:, MPRINT() and general source conditions. 2508/07/2001 - Enhanced Editor The enhanced editor shows the current cursor position in the bottom right corner of the status bar. An improvement could be to also show how many characters are selected when a select block is active. Also, since a fair amount of dynamic parsing is going on for syntax highlighting, the enhanced editor could also report in a status field, how deep into a string the cursor is. For example, if I have to change something at the fortieth character position in some text, I would like to be able to read that position for the status line instead of pressing right arrow forty times starting at the initial quote mark. The character position would also honor sequential character strings that might be found in title, footnote and note statements. (e.g. title "This is a" " valid " "title, made up of three quote delimited texts") 2407/26/2001 - Online Doc V8 - RXPARSE The example in the RXPARSE documentation incorrectly uses a grave () in the pattern. Leading grave was only necessary for v6.12. Additionally, the Functions and CALL routines book does not list all the RX family of functions. 2307/13/2001 - New automatic macro variables The base system could be improved in terms of providing two new global automatic macro variables: SYSREAL SYSCPU  The values of theses macro variables would be the same values as reported in the log. Having such numbers available allows production of benchmarking code and production of code that can more easily monitor itself. For example: ---- program ---- data _null_; do i = 1 to 1e8; end; run; %put sysreal=&sysreal; %put syscpu=&syscpu; ---- shows in the log ---- NOTE: DATA statement used: real time 2.35 seconds cpu time 2.31 seconds WARNING: Apparent symbolic reference SYSREAL not resolved. &sysreal WARNING: Apparent symbolic reference SYSCPU not resolved. &syscpu ----- The log could show this ---- Could become NOTE: DATA statement used: real time 2.35 seconds cpu time 2.31 seconds sysreal=2.35 syscpu=2.31 ----  2207/10/2001 - Information Labelling Today, tables and views can be labeled, catalog entries can be described. A possible improvement would be to allow labelling of Libnames or Catalogs. An additional or alternate information labelling technique would be to incorporate an 'About' attribute to ANY referenceable data object or data store. I would envision the 'About' value could point to an html file, indicate a command to execute or a program to run I know I could devise a scheme by adding an About action to everything accessed under Explorer Options, but I think a more robust framework would be provided if the About concept was embedded at the lowest level of the SAS system. So, essentially everything would eventually get an about= option 2107/10/2001 - Recent file list I am using version 8.2 In the File menu, I have increased the number of recent files from the default of 4 to 12. I often need to switch between many same-named files in different deep directory paths. Hence, the MRU list shows these long filenames with ... in them. (e.g. C:\...\myprogram.sas) I notice that the text in the status bar displays an informative message for menu items. But the status bar is blank when the mouse rolls over the MRU files. An improvement would be to place in the status bar the full filename of the file that would be opened. Example:  Open document "<full filename>"  I first saw this type of sensible feedback when using Softquad's HotMetal Pro 6. Office 97 exhibits non-sensible feedback and has the ... within MRU filenames and does not show full filenames in a status bar. I believe in 8.1 the menus where wider to accomodate the full filename (but I am not 100% sure). 2007/01/2001 - Windows enhanced editor The editor could be improved if this more choices could be added to the context menu for a selected text. • If the selected text represents an existing table, add the Explorer table context menu • If the selected text represents an existing catalog, add the Explorer catalog context menu If this is done, I can highlight a name of a table in my source code and open it directly off the context menu (as opposed to having to copy to buffer and typing VT [paste][enter] in the command window) 1906/13/2001 - PROC Format Proc format could be improved in this way. When a CNTLIN data set is specified, allow the format name to be specified as part of the proc invocation as opposed to being required in the data set data lookupTable; input lookupValue formattedValue; cards; ABC abc Bob BOB! Dun Done ; run; PROC Format CNTLIN = lookupTable (rename=(lookupValue=start formattedValue=label)) FMTNAME = '$lookup.'
;
run;

1806/13/2001 - PROC Transpose

Proc transpose could be improved by adding an option to transpose each row. This would eliminate the need to create a view to create a unique id variable that is used to Transpose BY.

1703/01/2001 - SAS/AF Metadata editor modality

The Metadata editor dialog should become non-modal and track content as appropriate.
This suggestion applies to all Metadata editors that can be invoked from editors such as Class Editor, Property Editor, Interface Editor etc.

Example:
Suppose I am working in the Propery Editor.
I use context menu selection Edit... over one of a components attributes listed on the right hand side table.
The Metadata Edit dialog opens and is modal, I cannot chose another attribute to edit until the dialog is closed and reopened.

The improvement would be to make the Edit dialog non-modal and allow a new context simply by left clicking on a different attribute.
The Edit dialog title would have to be more informative to show the actual attribute being edited.

More so, the Metadata editor would be cognizant of the context of the right hand side table. If so, when the left hand side tree is navigated to show methods in the right hand side table, and a left click occurred on a row, the Editor would reconfigure itself to be appropriate for method Metadata. I have seen this sort of dialog in Lotus Notes and Framemaker.

Additionally, conceptually all Metadata is simply SAS Institute categorized name value pairs (e.g. The tabber labels are the Metadata categories [not to be confused with the category metadata element in the Options metadata category]). Each Metadata editor lays out its categories in a functional visualization for us developers. It might be good to also develop a generic Metadata editor that can be optionally used (when a registry setting or other option indicates so). The generic Metadata editor would be a TreeView/ListView combination with the metadata categories in the treeview and the actual name value pairs in the listview.

Anything in a listview would theoretically be a candidate for having additional metadata, however I would not suggest going into that recursive snake eating it's tail arena [each metadata would be a name/nested list [which is sort of there anyway since a 'value' can be a list,object or class, etc...] instead of a simple name/value pair]

1603/01/2001 - New function for Base SAS and SAS/AF, TokenResolve( )

Many times I find myself working with the concept of 'building up' or 'assembling' a statement into a string where the string is later used to open a dataset or be replaced in a submit continue block.

A new function called something like resolve() or tokenResolve() would be a great help
For example suppose I have this SCL

firstName = 'Richard';
lastName = 'DeVenezia';

dsid = open ('Username(where=(lastname=' || quote(lastname)
|| ' and firstname=' || quote(firstName) || '))' );
if dsid > 0 then do;
...
rc = close (dsid);
end;


The above could be simplfied from a human readable standpoint if there was a tokenResolve() function.

dsToOpenTemplate = 'Username(where=(lastname="::lastName::" '
|| ' and firstName="::firstName::"))';
dsToOpenResolved = tokenResolve (dsToOpenTemplate, '::')
dsid = open (dsToOpenResolved);
...

tokenResolve would take arguments
- templatedString
- tokenStart
- tokenEnd
- recurseDepth


if tokenEnd is not specified it is the same as tokenStart. recurseDepth would force the resolver to recursively resolve resolved tokens to some maximum depth. default might be 1 and 0 could indicate infinite depth or errors out when recursive looping detected.

For each string found between the token delimiters, the corresponding variable is looked up in the current PDV and it's current value replaces the delimited token.

1502/26/2001 - Enhanced Editor, suggested features

I like the new editor, it makes my coding time productive.

Some SAS programs I write are very long. Some sections of code involve several data steps, proc sqls and other Procs.

It would be nice (with out resorting to macro blocks) to indicate a section that could be collapsable just like data steps, procs and macros can be collapsed. The indicate of any arbitrary collapsable block could be simply indicated with an options screen.

For example an options dialog might ask for strings that indicate the collapsed boundaries

Block starts with: /* Section
Block ends with
(ends with could be optional,
in which case the block continues to the next start block)


Additionally, nested collapsibility would be nice in obvious cases of do loops or do;/end; blocks in general. I grant this can be difficult or impossible when macro code is involved.

Certain teams or certain projects may work with different sets of editor parameters or options settings. It would nice if the editor settings could be indicated via some sort of style sheet.
For example:

/* @include Team1_editorSettings.sas */

and a file Team1_editorSettings.sas might have these lines
/*
* Who / What / When / Where / Why style comments
*
* @scheme: Retro
* @Comment:{Font:Arial}
*/
etc...


Maybe this could work as some sort of variant of CSS.

Finally, Options/settings for enforcing standards of code legibility would be nice (e.g. indentation, spaces between operators or function arguments, etc... similar to Microsoft Visual Basic)

1402/17/2001 - SAS/AF SCL editor, Windows Platform

When I copy code from the SCL editor window and paste it into another window the code contains many trailing blanks.

An improvement would be to strip the trailing spaces before placing the text into the copy buffer.

1312/06/2000 - PATHNAME( ) function

After reading SN-003758 I would suggest this:

Create a function PATHNAMELIST() which returns the first path and an SCL list of all the paths to the current results list (similar behaviour as CURLIST, DIRLIST, CATLIST, etc...).

1207/21/2000 - SAS Component Language: SORTLIST( ) function

The SCL tool could be improved by extending the functionality of SORTLIST.

The ability to sort lists of lists has become important in Version 8.
Adding an option such as SUBLISTVALUEOF=name or SUBLISTVALUEOF=position could let a developer sort a list of lists that is typically used with the new version 8 controls. (In Class editor parlance I suppose this is called sorting attributes by attribute property value)

Another alternative could be having an options NESTEDSORT and NESTEDOPTION in which a list is passed to indicate how to sort a multi-level list. A NESTEDSORT would sort sub-lists. The NESTEDOPTION list would contain the typicall OPTIONs but there would be a sub-list of the same for each level.

e.g.
* options for a list with three levels;
declare list NESTEDOPTION =
{ 'ASCENDING VALUE', { 'DESCENDING NAME', { 'ASCENDING NAME' } } };

1107/20/2000 - AF: Properties editor, Editor for attribute of type List

The List editor could be improved by adding a Sort Button with Ascending, Descending, and Case sensitivity options.

1007/19/2000 - AF: Improved syntax for list handling

The way SCL code interacts with SCL lists could be improved using an extension of the dot notation.

consider L

	declare list L;


since L has been declared a list, it should be allow special dot notation syntax for simplified list management

	L.itemname[itemname-index]


suppose the list has an item named X

	L.X = ...    (setnitem equivalent)
... = L.X    (getnitem equivalent)


suppose the list has N items named X

	L.X = ...    (setnitem of first X)
... = L.X    (getnitem of first X)
L.X[i] = ... (setnitem of i'th X)
... = L.X[i] (getnitem of i'th X)


suppose the list has N items

	L.[i] = ... (set value of i'th item)
... = L.[i] (get value of i'th item)

L.{itemname}[index] = ... (set value of i'th item with matching itemname)
... = L.{itemname}[index] (get value of i'th item with matching itemname)

Note:

L.X[i] is same as L.{'X'}[i]


There would be lots of gory details resolving issues surrounding itemtypes and negative indices.

0907/17/2000 - AF: Dual Selector Control

Since the Dual Selector Control is still experimental you might want to consider these ideas for deployment of a production version

- add a List View Control (call it Details) below the list boxes

- model/viewer ready for interface staticStringList interface
- model/viewer ready for interface 'List of Lists'
List of Lists is the structure returned in loadItems attributes of
all the 'meta-information' List Models.

A class attribute (say listItem (char)) would control which named
item in each sub-list would be shown in the list boxes.
A class attribute (say showDetail (list)) if populated would control
whether or not Details is visible and which named items are shown.


I assume I can make the 'meta-information' List Models deliver list of lists information by changing the defaultAttribute attribute from items to loadedItems.

- the up / down controls wrap top to bottom or bottom to top

- allow Listbox2 to be swapped out and a 'TreeViewControl2' to be
swapped in, presenting the selections in a 'always exploded' tree.  This
renders the selections in a hierarchy visualization. left button would
remove a level, double left button would remove level and children.

0807/13/2000 - Publication 55888 - SAS Guide to App Dev
=== 1. ===
The code sample on page 199 could be improved:

the sample has
--
dsid = open (table);
if dsid ne 0 then do;
levels=0;
rc=lvarlevel(dsid,columnName,levels,columnData);
end;
rc=close(dsid);

the close should occur within the then do block so an error will not occur
if the table could not be opened
also, a check should be done to ensure the columnName is in the table before
proceeding.
--
dsid = open (table);
if dsid ne 0 then do;
if varnum (dsid, columnName) > 0 then do;
levels=0;
rc=lvarlevel(dsid,columnName,levels,columnData);
rc=close(dsid);
end;
end;

=== 2.===
On page 199, at step 2 of creating a subclass of the list box my experience
was that the 'Add Methods' prompt did not occur unless I changed the status
default 'requires' to 'supports'.  After doing so and saying yes to the
prompt, I changed the status back to 'requires'

=== 3. ===
On page 200, the onContentsUpdated method uses a method 'getModelData()'.
This should be '_getModelData()'

=== 4. ===
On page 200, the setcamModel method uses a method 'getModelData()'.
This should be '_getModelData()'
Also, the setcamModel indicates a use of the '_super()' method.  The code
will not compile as such.
When I use the syntax '_super(attributeValue)' the sample code compiles, and
the example works as expected.

0707/06/2000 - AF: SAS/Share retrieving information

Presently, the only way I know how to obtain information about a SAS/Share server is to use Proc OPERATE. All the information this Proc provides is through output to the log window. As such, the information is rather unavailable for use in other programmatic applications.

An AF class interface should be implemented so as to make this information more malleable OR an OUT= option should be provided so as the current state of the server can be placed in a data set for further processing or analysis.

An improvement to Proc SERVER could also be made by also giving that Proc an OUT= option to capture the information that presently goes into the log file.

As for the AF class, at a minimum it should have a method to return an SCL list with one of these two useful hierarchies

Users
+=Libraries
+=DataSets
+=Catalogs

Or

Libraries
+=DataSets
+=Users
+=Catalogs
+=Users


### Elicited this response

Hi Richard,

While not exactly fitting either of the models you suggest, there IS an EXPERIMENTAL feature currently in Version 8 of SAS/SHARE that should be able to give you what you want. This feature is the "Administrative Engine" that provides a client-server pathway for such server status information as you seek.

To use this feature, use the following tips. With a V8 SAS/SHARE server started, a client SAS session can then issue a LIBNAME statement that uses a special "reserved" libref of SASADMIN, and which connects to the server with the SERVER=servername option. For example,

   LIBNAME SASADMIN SERVER=hostid.serverid;


Note: this libref CAN be changed if you specify a different name when starting the SAS/SHARE server; to do this, add the ADMINLIBREF= option to the PROC SERVER statement, such as:

   PROC SERVER ID=serverid ADMINLIBREF=FOO;


ALSO NOTE that this server option itself is subject to change in later releases of the server--the option name may change and/or the whole communication technique may change. This is the nature of such an experimental beast....

Having issued the LIBNAME statement, you can then do all manner of things, such as using PROC CONTENTS against the library to examine the datasets and their variables in this library. Currently, I believe, you'll find data sets named LIBRARY, SERVER, and USER, and the variables in each of these will be named appropriately for each of the "views." You should be able to examine these datasets using DATA step code or AF SCL code (which makes it more universal than having it load an SCL list). Currently, this is just a "read-only" feature--it won't do any PROC OPERATE administrative actions other than the DISPLAY command type actions. You can always have a DATA step build PROC OPERATE statements and submit these via CALL EXECUTE().

Hope this helps!
0607/05/2000 - AF: Meta list models

Certain models such as Catalog Entry List, Variable List and Variable Values List could be improved when used in linking.

The model which rely on a 'thing to open which contains items' attribute [e.g. catalog, dataSet and dataSet/variable] which must be specified with the appropriate 2 level name.

Adding attribute 'library' to these models would allow the library value (first level) to be linked to a one component and the catalog or dataset value (second level) to be linked to a second component.

This is appropriate when a model delivers values to a list box, whose selection is the 'linked To' value of another component AND the developer does not want the entire 2 or 4 level name shown in the list box.

0507/03/2000 - AF: Properties editor

The AF components properties editor used during build could be made more useful by implementing the following behaviour.

When a cell in the Category column is double-clicked, the attributes shown will restrict to only those of the type in cell double-clicked (zoom-in). If the attributes are already being restricted, then the attributes shown will revert to all categories of attributes (zoom-out).

This behaviour would eliminate mouse movement needed to change the attribute category being displayed via the left hand side properties tree view control.

0406/30/2000 - AF: Properties editor

The properties/attributes editor could be made more useful in several ways:

- allow the list of components to be sorted in different ways
- by Object type
- by 'last word' of Component name
(e.g. starting at last uppercase in component name)

- allow the attributes editing panel
(I am guessing this itself is a List View Control)
to improve in this way
- if cursor in Attribute Name column, row selection based on typing
- keypress X moves to next attribute that starts with X
- keypress XYZ moves to first next attribute that starts with XYZ
- have an automatic attribute category named 'recent'
- every time an attribute is modified, it is also copied into the
'recent' category
- when the user opens the recent category node, the kinds of attributes
(across all categories) they typically modify will be easily available
for selection

- attribute value cell editing
- make a change so that when the home key is pressed and then an arrow key
is pressed there is with-in value cell cursor motion, do not change the
active cell.  The current behaviour is annoying when I have to correct
the second or third character of a value.

0306/29/2000 - AF: SCL List declarations

The DCL LIST statement could be improved by allowing some 'options' to be specified, e.g.

DLC LIST  mylist = {'A', 'B', 'C', 1,2,3} (autoDelete=YES);


The autoDelete 'option' would cause the list to be automatically deleted whenever the code exits the current scope.

0204/13/2000 - AF: Class Editor, editing the Source Entry of a Method Name

The cursor motion when editing the Source Entry of a Method Name could be improved.

Presently, when the Source Entry is highlighted I can press the Home key to move the cursor to the start of the Source Entry value. However, when I press SHIFT-RIGHT ARROW at this point the highlighted cell becomes Source Label, instead of selecting the first character of the Source Entry. This is annoying when I have to change the library of a Source Entry.

When plausible, shift-arrow key should be a text selection action, not a = cursor cell motion action.

0111/24/1999 - Generating Variable Filenames

Submitted on my behalf


I really like Richard's idea described in the message below
I think a data set equivalent of FILEVAR on the file statement would be very
useful

Regards
Peter Crawford

Datum:         24.11.99 05:55
An:            SAS-L@listserv.uga.edu

Betreff:       Re: Generating Variable Filenames
Nachrichtentext:

This topic offers an interesting side thought.

If the FILE statement allows a FILEVAR= option to specify multiple
destinations from within a single data step, why is there not an OUTVAR=
option on the OUTPUT statement to allow the same type of multiple
destinations with output data sets ?

Where is the SAS ballot suggestion box when you need it ?

Richard

"Walter Smith" wrote in message
> No macros are needed, no multiple datasets, he wants it written to
> FILES named S01E2N01.dat etc. The following is tested, functional code:
>
> data eventdat;
>    infile cards;
>    input event evtype x1 x2;
> cards;
> 1 2 567 54.3
> 1 2 657 65.2
> 2 5 543 34.5
> 2 5 872 75.2
> 3 2 345 34.5
> 3 2 875 87.5
> ;
> proc sort data=eventdat;
>    by evtype event;
> data _null_;
>    set eventdat;
>    retain last_ev;
>    if event ne last_ev then do;
>       evnbr+1;
>       last_ev=event;
>    end;
>    length outfile \$15;
>    outfile='S'||put(event,z2.0)||'E'||
>       put(evtype,1.0)||'N'||put(evnbr,z2.0)||'.dat';
>    file dummy filevar=outfile;
>    put event evtype x1 x2;
> run;
>
> And the log shows:
>
> NOTE: The file DUMMY is:
>       File Name=/pathname/S01E2N01.dat,
> NOTE: The file DUMMY is:
>       File Name=/pathname/S03E2N02.dat,
> NOTE: The file DUMMY is:
>       File Name=/pathname/S02E5N03.dat,
> NOTE: 2 records were written to the file DUMMY.
> NOTE: 2 records were written to the file DUMMY.
> NOTE: 2 records were written to the file DUMMY.
> NOTE: DATA statement used:
>       real time           0.070 seconds
>       cpu time            0.026 seconds
>
> [some lines were deleted for brevity, others changed for security]
`

Richard A. DeVenezia