It is important to know the differences between explicit descriptor argument types (e.g., i) and ambiguous descriptor types (e.g., n). This article addresses some common misconceptions and mistakes developers make when converting and using Synergy routine parameters. The n parameter type allows any numeric type (d, d., p, p., or i) to be passed in. MISMATCH n allows an a type to be passed in as well. Be careful when passing n parameters to other routines that are not marked n. For example, if an integer literal is passed to an n argument (note that the default type for the literal in the compiler is integer when passed to an n parameter, and prototyping helps the compiler know the argument type), and that parameter is then passed to a subroutine whose parameter is declared as d, the runtime would get an unexpected decimal value that is not the same as the literal.
The compiler in 10.3.3c+ has been enhanced to provide a DBL-W-PASSUR warning in the n to d/d. or n to i situation (which assumes your code is fully prototyped to detect this). Below are several techniques to resolve these warnings. In addition, the traditional compiler has been enhanced to convert the parameter to the correct i or d type if the parameter is declared as IN without a warning. (The .NET compiler already performed this conversion.) The compiler always produces a warning for n to d. When built with the -W4 compiler option, these silent conversions get a PASSIMPL warning.
- ^I, ^A, ^D, and ^F do not convert a variable from one type to another. The proper way to think of this is “Treat this variable as this kind of variable.” These data reference operations should only be employed when you run into a situation where you need a heavy-handed “programmer knows best” solution, like a cast or to help overload resolution. Conversion routines are available, such as %INTEGER for i types, %IMPLIED for d., and in a version after 10.3.3c, %DECIMAL for d types. See the second to last bullet below for methods.
- If possible, always be data-type specific when declaring parameter types. For example, if you\'re passing to an i that’s always used as an i type, make the parameter an i. Try to be consistent when using n types, to ensure that all routines called in the path of an n parameter also take n, or ensure the n parameter is converted to the correct type. In many cases, changing the called routine parameter to n is the correct answer, rather than actually converting to the called routine parameter type.
- If you use a parameter as a ^M memory handle, it should be declared as a D_HANDLE parameter type. Note that D_HANDLE is really an i4; therefore, to avoid a type mismatch error or the loss of data, an i4 should be expected anywhere D_HANDLE is used.
- When using the %IMPLIED and %INTEGER routines to convert a parameter to another routine argument, it is assumed that the argument in the called routine is IN only, which means it won’t work properly if the argument is being written to. For example, if %IMPLIED is used to convert an n parameter to a d argument, you should modify the called routine parameter to be an explicit IN if the direction is unspecified. If it is not IN, pass the argument to a local variable of the explicit d. type.
- %DECIMAL cannot be used to convert an n parameter to a d argument. You must either use a local temporary d field or use ^D(%IMPLIED(%RND(arg))) to convert the argument to a whole number with 0 decimal places and then cast to a ^D. If you want truncation instead of rounding, %TRUNC() can be used. Failure to do this can cause the d field to get a large number for an implied-decimal parameter. A level 3 PASSUR warning helps identify these cases.
- Be careful when using %INTEGER on an n parameter that is actually implied decimal, as the default rounding rules may round the implied value up. If you do not want implied rounding, use %TRUNC first.
- It is not necessary to use ^ARGTYPE to see if an n parameter is an i type before using %IMPLIED to a d routine. The overhead of ^ARGTYPE and %IMPLIED are similar.
- When using class methods overloads with specific type parameters, and one overload is using type n, the compiler always resolves to the specific type unless the match uses an n parameter at the call site. If the n routine needs to call the specific routines, you must explicitly cast the n parameter to the required type using ^I, ^D, or ^F to call the specific routine overload. Synergex recommends using either explicit type overloads or just a single n parameter method (not both) due to the overhead of multiple call depths. See the routine below for an example of multiple overloads.
- When using MISMATCH n, always use ^ARGTYPE to determine if the type is really alpha, and then explicitly cast using ^A() when passing an argument to a routine taking an explicit a argument. You must explicitly cast a MISMATCH n argument as (n) if you want it to match an n parameter.
; How to write a multiple overload method with n, i, and d overloads
method Mymethod, void
using ^argtype(Mynumeric) select
(D_TYPE_ID),Mymethod(Myarg, ^D(Mynumeric, ^argprecision(2))
(),nop ;throw some exception
method Mymethod, void
THE INFORMATION PROVIDED TO YOU IN THIS SERVICE IS FOR YOUR USE ONLY. THE INFORMATION MAY HAVE BEEN DEVELOPED INTERNALLY BY SYNERGEX OR BY EXTERNAL SOURCES. SYNERGEX MAKES NO WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS INFORMATION, INCLUDING THE WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SYNERGEX BE LIABLE FOR ANY DAMAGES OR LOSSES INCURRED BY YOU IN USING OR RELYING ON THIS INFORMATION, INCLUDING WITHOUT LIMITATION GENERAL DAMAGES, DIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES, OR LOSS OF PROFITS, EVEN IF SYNERGEX HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.