All numeric strings being compared as numbers instead of as strings

208 views
Skip to first unread message

David Laansma

unread,
Jul 10, 2017, 10:39:20 AM7/10/17
to Pick and MultiValue Databases
Greetings Team,

I have two variables:

THIS.ELEMENT = 0001234556789
LAST.ELEMENT = 0123456789

The values for these was attained from using the REMOVE statement.

The problem is this statement:

IF THIS.ELEMENT = LAST.ELEMENT THEN x

Is resolving to TRUE because it thinks they are numbers, and numerically they are the same.

I need them to compare as strings, thus resolving to FALSE.

How do I get these two variables to compare as strings instead of numbers?

Martin Phillips

unread,
Jul 10, 2017, 10:55:03 AM7/10/17
to mvd...@googlegroups.com

This is correct behaviour as documented.

 

If you are on U2 or QM, use the COMPARE() function. For other environments you need to force a string comparison by doing something contrived such as

   IF A:'X' = B:'X' THEN …

to add the same non-numeric suffix to both strings.

 

 

Martin Phillips
Ladybridge Systems Ltd
17b Coldstream Lane, Hardingstone, Northampton NN4 6DB, England
+44 (0)1604-709200

--
You received this message because you are subscribed to
the "Pick and MultiValue Databases" group.
To post, email to: mvd...@googlegroups.com
To unsubscribe, email to: mvdbms+un...@googlegroups.com
For more options, visit http://groups.google.com/group/mvdbms

David A. Green

unread,
Jul 10, 2017, 11:00:06 AM7/10/17
to mvd...@googlegroups.com

SCMP(x, y)

Returns -1 if x<y

Returns 0 if x=y

Returns 1 if x>y

 

OR

 

X:” “ = y:” “

 

David A. Green

(480) 201-7953

DAG Consulting

 

From: mvd...@googlegroups.com [mailto:mvd...@googlegroups.com] On Behalf Of David Laansma
Sent: Monday, July 10, 2017 7:39 AM
To: Pick and MultiValue Databases <mvd...@googlegroups.com>
Subject: [mvdbms] All numeric strings being compared as numbers instead of as strings

 

Greetings Team,

--

Dan Ell

unread,
Jul 10, 2017, 11:11:40 AM7/10/17
to mvd...@googlegroups.com, Dan Ell

IF THIS.ELEMENT:’X’ = LAST.ELEMENT:’X’ THEN

      True…

END ELSE

      False…

END

 


Dan Ell
Technical Support Engineer
P: 949-383-2429
E: da...@jbase.com | W: jbase.com
A: 9245 Research Drive, Irvine, CA 92618

From: mvd...@googlegroups.com [mailto:mvd...@googlegroups.com] On Behalf Of David Laansma


Sent: Monday, July 10, 2017 10:39 AM
To: Pick and MultiValue Databases <mvd...@googlegroups.com>
Subject: [mvdbms] All numeric strings being compared as numbers instead of as strings

 

Greetings Team,

--

David Laansma

unread,
Jul 10, 2017, 12:43:19 PM7/10/17
to Pick and MultiValue Databases
Thank you everyone. One nugget of information is that I'm on Unidata.

Here are the results of my tests with your various suggestions:

1. I find no documentation on a COMPARE () function in the Rocket Unidata Unibasic Commands Reference Version 8.1.0 document.
2. The SCMP function returned zero, indicating the two strings were the same.
3. IF A:"X" = B:"X" THEN X worked, perfectly logical.

I understand why it's doing what it's doing, but I would think there's a function that would do this for me.

Dick Thiot

unread,
Jul 10, 2017, 3:12:46 PM7/10/17
to mvd...@googlegroups.com
It sounds like SCMP is the function that you are looking for.  I suggest that you try with other strings that are different to see if it returns -1 or 1 as David Green suggested.

--
You received this message because you are subscribed to
the "Pick and MultiValue Databases" group.
To post, email to: mvd...@googlegroups.com
To unsubscribe, email to: mvdbms+unsubscribe@googlegroups.com

Dan McGrath

unread,
Jul 10, 2017, 3:21:02 PM7/10/17
to mvd...@googlegroups.com
SCMP is explicitly not what you are looking for. It is designed to compare very large numbers (as strings) to avoid the whole issue of floating point rounding. I'd stick with forcing it to be a string as I don't think UniData has an dedicated function for it.

Tony Gravagno

unread,
Jul 10, 2017, 4:17:53 PM7/10/17
to Pick and MultiValue Databases
What it IS doing for you is recognizing that the data is a number and thus doing a numeric comparison. For some this is a feature and for others it's an annoyance. This is the beauty and folly of the MVDBMS where variables are Not strongly typed. You'll get similar results in other languages that aren't strongly typed. For similar folly consider that in JavaScript and PHP there are two equality operators and both languages interpret zero/null/emptystring differently.

As to "I think there would be a function". You have it. Concatenating a string to a variable forces it to be a string. That's simply different syntax from what you're looking for where you might have something like IFA for an If-Alpha comparison, or ALPHA(VAR) to force a string.

For MVDBMS where BASIC allows user-defined functions, you can indeed create a function that does a comparison after forcing to string. The platform isn't just WYSIWYG, it's "the tools are in there for you to do all kinds of stuff" ... which makes for an awful acronym so you never see it documented. ;)

frosty

unread,
Jul 10, 2017, 4:48:48 PM7/10/17
to Pick and MultiValue Databases
On Monday, July 10, 2017 at 10:43:19 AM UTC-6, David Laansma wrote:
Thank you everyone. One nugget of information is that I'm on Unidata.

Here are the results of my tests with your various suggestions:

1. I find no documentation on a COMPARE () function in the Rocket Unidata Unibasic Commands Reference Version 8.1.0 document.
2. The SCMP function returned zero, indicating the two strings were the same.
3. IF A:"X" = B:"X" THEN X worked, perfectly logical.

I understand why it's doing what it's doing, but I would think there's a function that would do this for me.


You can write your own functions in uniData:
FUNCTION STRINGS_ARE_EQUAL(STRING1,STRING2)
RETURN '"':STRING1:'"' = '"':STRING2:'"'


Compile and Catalog the function, then call it via:
IF STRINGS_ARE_EQUAL(THIS.ELEMENT,LAST.ELEMENT) THEN x

frosty

unread,
Jul 10, 2017, 4:51:44 PM7/10/17
to Pick and MultiValue Databases
Ooops, forgot to say you need to add the reference to the new function to the calling program:
DEFFUN STRINGS_ARE_EQUAL(STRING1,STRING2) CALLING 'STRINGS_ARE_EQUAL'

Ed Clark

unread,
Jul 10, 2017, 5:12:22 PM7/10/17
to mvd...@googlegroups.com
If your example code contains literally:
THIS.ELEMENT = 0001234556789
LAST.ELEMENT = 0123456789
then the unquoted numeric strings will be parsed as numbers, and stored in the variables as canonical numbers, losing the leading zeros from the get-go. Mentioning that is kind of like tech support asking if your computer is plugged in, but you never know…..

I imagine that there is no intrinsic function already because most people want the default behavior. If you don’t want the default behavior then, even if there were an intrinsic function, you would have had to code it to use the function, and it’s just as easy to code \IF X:””=Y:”” THEN ...\ as it is to code \IF NUMERICCOMPARE(X,Y)=0 THEN …\. 





--
You received this message because you are subscribed to
the "Pick and MultiValue Databases" group.
To post, email to: mvd...@googlegroups.com
To unsubscribe, email to: mvdbms+un...@googlegroups.com

David Laansma

unread,
Jul 11, 2017, 8:45:31 AM7/11/17
to mvd...@googlegroups.com
Frosty,

This is the most effective solution thus far. Thank you.

--
You received this message because you are subscribed to
the "Pick and MultiValue Databases" group.
To post, email to: mvd...@googlegroups.com
To unsubscribe, email to: mvdbms+unsubscribe@googlegroups.com

For more options, visit http://groups.google.com/group/mvdbms



--
Sincerely,
Dave Laansma

Kevin Powick

unread,
Jul 11, 2017, 11:45:05 AM7/11/17
to Pick and MultiValue Databases

On Monday, 10 July 2017 16:17:53 UTC-4, Tony Gravagno wrote:
... consider that in JavaScript and PHP there are two equality operators and both languages

Maybe it would be useful to add the "double equal" operator to MV to check equality of both the type and value?  e.g. IF X == Y THEN
 
As to "I think there would be a function". You have it. Concatenating a string to a variable forces it to be a string. That's simply different syntax

That's really a bit of a hack because "forcing" the values to be compared as strings can be done so arbitrarily, leading to inconsistent code.

Anyway, it's not often we run into this, so I expect that the status quo will be maintained

--
Kevin Powick

Martin Phillips

unread,
Jul 11, 2017, 12:05:07 PM7/11/17
to mvd...@googlegroups.com

Hi Kevin,

 

QM has the double equals

   IF A == B THEN …

to force a string comparison. There is no need for a numeric equivalent as the ordinary = relational operator converts to numeric if it can.

 

 

Martin Phillips
Ladybridge Systems Ltd
17b Coldstream Lane, Hardingstone, Northampton NN4 6DB, England
+44 (0)1604-709200

 

 

 

From: mvd...@googlegroups.com [mailto:mvd...@googlegroups.com] On Behalf Of Kevin Powick


Sent: 11 July 2017 16:45
To: Pick and MultiValue Databases

--

You received this message because you are subscribed to
the "Pick and MultiValue Databases" group.
To post, email to: mvd...@googlegroups.com

To unsubscribe, email to: mvdbms+un...@googlegroups.com

Kevin Powick

unread,
Jul 11, 2017, 12:10:01 PM7/11/17
to Pick and MultiValue Databases
That's great, Martin.  I didn't realize that. 

Just another reason to love QM.

--
Kevin Powick

Tony Gravagno

unread,
Jul 17, 2017, 9:26:43 PM7/17/17
to Pick and MultiValue Databases
And soon in D3 as well...

Kevin Powick

unread,
Jul 18, 2017, 4:44:36 PM7/18/17
to Pick and MultiValue Databases


On Monday, 17 July 2017 21:26:43 UTC-4, Tony Gravagno wrote:
And soon in D3 as well...

Really?  UDFs in D3?  That will be nice.

--
Kevin Powick

Tony Gravagno

unread,
Jul 18, 2017, 8:33:57 PM7/18/17
to Pick and MultiValue Databases
Yeah, I've been begging for it for years. Last year they actually announced that it's on the roadmap. We can't hold them to a timeline but I'm hoping we'll see it by 10.3.

Peter McMurray

unread,
Jul 19, 2017, 6:43:40 PM7/19/17
to Pick and MultiValue Databases
Perhaps somebody can explain exactly what they perceive to be the difference between UDF and a subroutine either included internally on compile or simply called externally. D3 does both extremely well.
I use them for things like stripping comma delimiters (ThankYou Grigory for a quick and easy solution) splitting numbers into words as used on cheques, setting up printers etc.etc.

Ed Clark

unread,
Jul 19, 2017, 10:34:41 PM7/19/17
to mvd...@googlegroups.com
It’s probably just a choice of coding style? with udf you can write compact constructs like:
  LOOP
    …
  UNTIL MyFunDone() DO REPEAT

while a CALL or GOSUB requires another statement and a variable to pass the result. Or if you have several operations to perform:
  ok=MyFunTransmit( MyFunURLEncode( MyFunStripAM(something)))

Some people really hate subroutine calls that have side effects like modifying parameters, but like function calls because there is an obvious result.

The downside is that you have to declare a user defined function, but most applications of any size will probably (hopefully) have a set of standard include files to do that in anyway.
But declaration is also an upside, because then you know what functions are being called. Typos get caught, etc.

On universe and unidata, user-defined functions an also be used in i-type expressions with SUBR() (IIRC)

On Jul 19, 2017, at 6:43 PM, Peter McMurray <pgmcm...@gmail.com> wrote:

Perhaps somebody can explain exactly what they perceive to be the difference between UDF and a subroutine either included internally on compile or simply called externally. D3 does both extremely well.
I use them for things like stripping comma delimiters (ThankYou Grigory for a quick and easy solution) splitting numbers into words as used on cheques, setting up printers etc.etc.

John R. Stokka

unread,
Jul 20, 2017, 10:33:21 AM7/20/17
to mvd...@googlegroups.com
This should work

IF THIS.ELEMENT:'x' = LAST.ELEMENT:'x' THEN x

John R. Stokka
(515) 707-7106

Kevin Powick

unread,
Jul 20, 2017, 11:14:51 AM7/20/17
to Pick and MultiValue Databases
Compared to CALLed subroutines, UDF returns a result, not updated param values.  Result = MyUDF(p1,p2,...)

Compared to CALLed subroutines, Params of the UDF are passed by value, so immutable by UDF to calling program.

Compared to INCLUDEd code, Variables in UDF are local to the function only.  i.e. No global variables. 

Compared to INCLUDEd code, If UDF changes, no need to recompile programs using the UDF

--
Kevin Powick

Kevin King

unread,
Jul 20, 2017, 12:54:30 PM7/20/17
to mvd...@googlegroups.com
Is that standard across mv implementations, that parameters passed to functions are immutable?

--
You received this message because you are subscribed to
the "Pick and MultiValue Databases" group.
To post, email to: mvd...@googlegroups.com
To unsubscribe, email to: mvdbms+unsubscribe@googlegroups.com

Ed Clark

unread,
Jul 20, 2017, 2:01:25 PM7/20/17
to mvd...@googlegroups.com
On Jul 20, 2017, at 12:54 PM, Kevin King <precis...@gmail.com> wrote:

Is that standard across mv implementations, that parameters passed to functions are immutable?


NO. universe, unidata, jBase, and Caché all pass function parameters by reference, just like subroutines.

To unsubscribe, email to: mvdbms+un...@googlegroups.com

Steve Johnson

unread,
Jul 20, 2017, 2:46:02 PM7/20/17
to mvd...@googlegroups.com
If you want to pass an argument by value, just enclosed it in parentheses. This makes it an expression.

Regards,
Steve Johnson
Progenixx, Inc.

David A. Green

unread,
Jul 20, 2017, 3:17:36 PM7/20/17
to mvd...@googlegroups.com

Forgot about that trick.  Works in UniData.

To unsubscribe, email to: mvdbms+un...@googlegroups.com

--
You received this message because you are subscribed to
the "Pick and MultiValue Databases" group.
To post, email to: mvd...@googlegroups.com

To unsubscribe, email to: mvdbms+un...@googlegroups.com

--
You received this message because you are subscribed to
the "Pick and MultiValue Databases" group.
To post, email to: mvd...@googlegroups.com

To unsubscribe, email to: mvdbms+un...@googlegroups.com

--
You received this message because you are subscribed to
the "Pick and MultiValue Databases" group.
To post, email to: mvd...@googlegroups.com

To unsubscribe, email to: mvdbms+un...@googlegroups.com

Kevin Powick

unread,
Jul 20, 2017, 4:09:59 PM7/20/17
to Pick and MultiValue Databases


On Thursday, 20 July 2017 12:54:30 UTC-4, Kevin King wrote:
Is that standard across mv implementations, that parameters passed to functions are immutable?

In QM you can, optionally, specify params as IN or OUT. 

   MyUDF(IN:A, IN:B, OUT:C)

IN params remain unaltered to the calling program, retaining their original values.  OUT params return values from the UDF, but their initial value is ignored by the UDF.  Params with neither IN/OUT are bi-directional.  Their initial value is sent to the UDF, and altered values are sent back to the calling program, just like a CALLed subroutine.

--
Kevin Powick

 

On Jul 20, 2017 9:14 AM, "Kevin Powick" <kpo...@gmail.com> wrote:
Compared to CALLed subroutines, UDF returns a result, not updated param values.  Result = MyUDF(p1,p2,...)

Compared to CALLed subroutines, Params of the UDF are passed by value, so immutable by UDF to calling program.

Compared to INCLUDEd code, Variables in UDF are local to the function only.  i.e. No global variables. 

Compared to INCLUDEd code, If UDF changes, no need to recompile programs using the UDF

--
Kevin Powick

On Wednesday, 19 July 2017 18:43:40 UTC-4, Peter McMurray wrote:
Perhaps somebody can explain exactly what they perceive to be the difference between UDF and a subroutine either included internally on compile or simply called externally. D3 does both extremely well.
I use them for things like stripping comma delimiters (ThankYou Grigory for a quick and easy solution) splitting numbers into words as used on cheques, setting up printers etc.etc.

--
You received this message because you are subscribed to
the "Pick and MultiValue Databases" group.
To post, email to: mvd...@googlegroups.com
To unsubscribe, email to: mvdbms+un...@googlegroups.com

David A. Green

unread,
Jul 20, 2017, 4:37:41 PM7/20/17
to mvd...@googlegroups.com

UniData will allow you to change Function arguments.

 

Plus, you cannot use a Function in an I-Descriptor in UniData only Subroutines.

From: mvd...@googlegroups.com [mailto:mvd...@googlegroups.com] On Behalf Of Kevin King
Sent: Thursday, July 20, 2017 9:54 AM
To: mvd...@googlegroups.com

To unsubscribe, email to: mvdbms+un...@googlegroups.com

--

You received this message because you are subscribed to
the "Pick and MultiValue Databases" group.
To post, email to: mvd...@googlegroups.com

To unsubscribe, email to: mvdbms+un...@googlegroups.com

Wols Lists

unread,
Jul 20, 2017, 5:54:10 PM7/20/17
to mvd...@googlegroups.com
On 20/07/17 03:34, 'Ed Clark' via Pick and MultiValue Databases wrote:
> It’s probably just a choice of coding style? with udf you can write
> compact constructs like:
> LOOP
> …
> UNTIL MyFunDone() DO REPEAT
>
> while a CALL or GOSUB requires another statement and a variable to pass
> the result. Or if you have several operations to perform:
> ok=MyFunTransmit( MyFunURLEncode( MyFunStripAM(something)))
>
> Some people really hate subroutine calls that have side effects like
> modifying parameters, but like function calls because there is an
> obvious result.
>
> The downside is that you have to declare a user defined function, but
> most applications of any size will probably (hopefully) have a set of
> standard include files to do that in anyway.
> But declaration is also an upside, because then you know what functions
> are being called. Typos get caught, etc.
>
> On universe and unidata, user-defined functions an also be used in
> i-type expressions with SUBR() (IIRC)

Certainly in UniVerse, there is no real difference between how functions
and subroutines are implemented. You can write a function and call it as
a subroutine, or write a subroutine and call it as a function.

All that matters is that it has at least one argument, and that the
first argument is not needed to pass anything in to the routine.

If you define it as a function in the calling routine, the compiler adds
an extra argument at the start of the argument list, then uses the value
returned in that argument as the result of the function. It just makes
life simpler and easier for the programmer.

Likewise, if you define it as a function in the function itself, it
assumes the existence of this hidden variable in the argument list.

Which is why, in Pr1me InfoBasic, the declarations SUBROUTINE and
PROGRAM were completely interchangeable, and FUNCTION almost so.

Cheers,
Wol

Peter McMurray

unread,
Jul 21, 2017, 8:41:03 PM7/21/17
to Pick and MultiValue Databases
Thanks for the UDF responses. For a moment I thought that I might have missed something, now I realise that there is no standard implementation.
We have included what we called functions since 1977. Typically these are items such as setting up complex keys for files or setting limits and strings. We have every variable for a system, not just a file, defined in a global dictionary that is used to set input parameters and define file contents. The simplest I can think of is Y or N for a question that is included in the code that calls the standard edit routine and the most complex is a 1000 line subroutine that does all the complex price calculations for the system. In our latest design that subroutine is dramatically shortened as we define a separate File Control routine for each file so that external sources can use the same file controls as the standard Basic programs.
I can see the point for intrinsic routines such as @AM and Oconv/Iconv but UDFs seem to me to be just another idea that will not be compatible across platforms. 
D3 has for many years advocated the use of breaking code into small less complex routines, to which I would add always use dimensioned arrays. The increase in speed when more than one element is accessed is orders of magnitude. I still remember with horror the disastrous change made by somebody in R83 who took one of the best programs ever written that brought floppy data in. A change in the floppy addressing required a simplistic change to the superbly written and documented routine. This clown decided to redimension the array every time they extracted a record from the flat file instead of dimensioning the array for the required number of records and simply slotting them in. The speed increase still applies today when handling things like Credit Card Records or importing debtor records to a new system from a non Pick source. We simply use a subroutine to split the comma delimited items to Pick items one at a time..
Reply all
Reply to author
Forward
0 new messages