L (l) suffix Bug, not always "Long", WIN-FBC64

General FreeBASIC programming questions.
fxm
Posts: 9980
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: L (l) suffix Bug, not always "Long", WIN-FBC64

Postby fxm » Apr 23, 2018 18:25

@MrSwiss:
I think you are best placed to fill in the bug report.
But if you do not have free time, I can take it (but with my own vision!).
MrSwiss
Posts: 3631
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: L (l) suffix Bug, not always "Long", WIN-FBC64

Postby MrSwiss » Apr 23, 2018 18:43

@fxm, done: #879 Type suffix, invalid on negative value literal number ...
dodicat
Posts: 6718
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: L (l) suffix Bug, not always "Long", WIN-FBC64

Postby dodicat » Apr 23, 2018 19:14

Not just - operator.
Any of + - * / affects literal long on 64 bit.

Code: Select all

 


print sizeof(123444ul)
print sizeof(+123444ul)


sleep
 
fxm
Posts: 9980
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: L (l) suffix Bug, not always "Long", WIN-FBC64

Postby fxm » Apr 23, 2018 19:48

dodicat wrote:Not just - operator.
Any of + - * / affects literal long on 64 bit.
OK when an explicit '+' sign precedes the integer literal.
The other operators correspond to real expressions where coercion of numeric data types applies normally.

Documentation updated again:
ProPgLiterals → fxm [Added a note on "negative" integer literal with a size suffix, or when an explicit '+' sign precedes the integer literal]

Added a note also in the bug report #879.
coderJeff
Site Admin
Posts: 3342
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: L (l) suffix Bug, not always "Long", WIN-FBC64

Postby coderJeff » Apr 29, 2018 16:02

Thank-you MrSwiss. There was a time when I wrote quite a bit of documentation for fbc. Rationally, unfortunate that this detail was missed. Emotionally, I take it as failure. However I feel that calling this "nonsense" is unjustified. Hopefully, this comes across as the rational response.

fxm, thank-you for your continued efforts on quality documentation.

fbc regularly coerces data from one datatype to another without any error or warning. It's what allows adding integers to floats, bytes to pointers, and so on. Without implicit coercion, every operation would require explicit casting by the programmer to a common data type; a real pain.

Presently, in fbc,
1) negate '-' is an operator separate from any literal.
2) '-', when used with #define SYM or CONST SYM or dec/hex/oct LITERAL, should all produce identical results.
3) smaller data types will be promoted to larger (platform preferred) data types to allow for constant folding, better code generation, etc, later anyway.
Aside from being missed in the documentation, overall is consistent behaviour.

To experiment, I wrote a partial bug fix for this issue, which you can find at bugfix-879. It's very rough (Specifically, in sources, FBVALUE should remain untouched, it's used in several structures, and instead, AST_NODE_CONST structure should be added, which will require changes throughout the code base; as paul doe points out, a fundamental change to fbc parser).

To contrast the before and after, here's an example I wrote that focuses on LONG type suffix '&' in fbc-32bit:

Before:

Code: Select all

#print typeof( 1 )       '' integer
#print typeof( -1 )      '' integer

#print ---
#print typeof( 1& )      '' long
#print typeof( -1& )     '' integer
#print typeof( -(1&) )   '' integer
#print typeof( --1& )    '' integer
#print typeof( --(1&) )  '' integer
#print typeof( -1&+0& )  '' integer
#print typeof( 0&-1& )   '' integer

#print ---
#define d1 1&
#print typeof( d1 )      '' long
#print typeof( -d1 )     '' integer
#print typeof( -(d1) )   '' integer
#print typeof( --d1 )    '' integer
#print typeof( --(d1) )  '' integer
#print typeof( -d1+0& )  '' integer
#print typeof( 0&-d1 )   '' integer

#print ---
const c1 as long = 1
#print typeof( c1 )      '' long
#print typeof( -c1 )     '' integer
#print typeof( -(c1) )   '' integer
#print typeof( --c1 )    '' integer
#print typeof( --(c1) )  '' integer
#print typeof( -c1+0& )  '' integer
#print typeof( 0&-c1 )   '' integer

#print ---
const c2 = 1&
#print typeof( c2 )      '' long
#print typeof( -c2 )     '' integer
#print typeof( -(c2) )   '' integer
#print typeof( --c2 )    '' integer
#print typeof( --(c2) )  '' integer
#print typeof( -c2+0& )  '' integer
#print typeof( 0&-c2 )   '' integer

#print ---
const c3 as long = -1
#print typeof( c1 )      '' long
#print typeof( -c1 )     '' integer
#print typeof( -(c1) )   '' integer
#print typeof( --c1 )    '' integer
#print typeof( --(c1) )  '' integer
#print typeof( -c1+0& )  '' integer
#print typeof( 0&-c1 )   '' integer

#print ---
const c4 = -1&
#print typeof( c2 )      '' long
#print typeof( -c2 )     '' integer
#print typeof( -(c2) )   '' integer
#print typeof( --c2 )    '' integer
#print typeof( --(c2) )  '' integer
#print typeof( -c2+0& )  '' integer
#print typeof( 0&-c2 )   '' integer

#print ---
#print typeof( &h1& )      '' long
#print typeof( -&h1& )     '' integer
#print typeof( -(&h1&) )   '' integer
#print typeof( --&h1& )    '' integer
#print typeof( --(&h1&) )  '' integer
#print typeof( -&h1&+&h0& )  '' integer
#print typeof( &h0&-&h1& )   '' integer

#print ---
#define d1 1&
#print typeof( d1 )      '' long
#print typeof( -d1 )     '' integer
#print typeof( -(d1) )   '' integer
#print typeof( --d1 )    '' integer
#print typeof( --(d1) )  '' integer
#print typeof( -d1+0& )  '' integer
#print typeof( 0&-d1 )   '' integer


Notice where CONST SYM and #define SYM differ with the bug fix. That means negate '-' behaviour will depend on if the symbol is a #define or a CONST, maybe that's OK if properly documented.

After bugfix-879:

Code: Select all

#print typeof( 1 )       '' integer
#print typeof( -1 )      '' integer

#print ---
#print typeof( 1& )      '' long
#print typeof( -1& )     '' long
#print typeof( -(1&) )   '' long
#print typeof( --1& )    '' long
#print typeof( --(1&) )  '' long
#print typeof( -1&+0& )  '' integer
#print typeof( 0&-1& )   '' integer

#print ---
#define d1 1&
#print typeof( d1 )      '' long
#print typeof( -d1 )     '' long
#print typeof( -(d1) )   '' long
#print typeof( --d1 )    '' long
#print typeof( --(d1) )  '' long
#print typeof( -d1+0& )  '' integer
#print typeof( 0&-d1 )   '' integer

#print ---
const c1 as long = 1
#print typeof( c1 )      '' long
#print typeof( -c1 )     '' integer
#print typeof( -(c1) )   '' integer
#print typeof( --c1 )    '' integer
#print typeof( --(c1) )  '' integer
#print typeof( -c1+0& )  '' integer
#print typeof( 0&-c1 )   '' integer

#print ---
const c2 = 1&
#print typeof( c2 )      '' long
#print typeof( -c2 )     '' integer
#print typeof( -(c2) )   '' integer
#print typeof( --c2 )    '' integer
#print typeof( --(c2) )  '' integer
#print typeof( -c2+0& )  '' integer
#print typeof( 0&-c2 )   '' integer

#print ---
const c3 as long = -1
#print typeof( c1 )      '' long
#print typeof( -c1 )     '' integer
#print typeof( -(c1) )   '' integer
#print typeof( --c1 )    '' integer
#print typeof( --(c1) )  '' integer
#print typeof( -c1+0& )  '' integer
#print typeof( 0&-c1 )   '' integer

#print ---
const c4 = -1&
#print typeof( c2 )      '' long
#print typeof( -c2 )     '' integer
#print typeof( -(c2) )   '' integer
#print typeof( --c2 )    '' integer
#print typeof( --(c2) )  '' integer
#print typeof( -c2+0& )  '' integer
#print typeof( 0&-c2 )   '' integer


#print ---
#print typeof( &h1& )      '' long
#print typeof( -&h1& )     '' long
#print typeof( -(&h1&) )   '' long
#print typeof( --&h1& )    '' long
#print typeof( --(&h1&) )  '' long
#print typeof( -&h1&+&h0& )  '' integer
#print typeof( &h0&-&h1& )   '' integer

#print ---
#define d1 1&
#print typeof( d1 )      '' long
#print typeof( -d1 )     '' long
#print typeof( -(d1) )   '' long
#print typeof( --d1 )    '' long
#print typeof( --(d1) )  '' long
#print typeof( -d1+0& )  '' integer
#print typeof( 0&-d1 )   '' integer


Now try, negate '-' used with literals having UNSIGNED suffixes:

Before ('-' is separate operator)':

Code: Select all

#print typeof( 1ul )       '' ulong
#print typeof( -1ul )      '' integer
#print typeof( +1ul )      '' uinteger


After bugfix-879 ('-' is supposed to respect literal datatype):

Code: Select all

#print typeof( 1ul )       '' ulong
#print typeof( -1ul )      '' long
#print typeof( +1ul )      '' ulong


Does this make sense? Not really. What is "-1ul" supposed to be? Error? If properly documented, should explain to the user what's going on here.

I dunno, the bug "fix" is looking like it introduces more inconsistencies than it resolves. Like, we are going to have more rules and exceptions to document, rather that fewer.

I am hoping that this (lengthy) response 1) gives some idea why this "bug" is not simply nonsense, 2) that I listen to your concern seriously, and 3) that I am not some faceless and heartless corporation offering only the response of "by design" with zero explanation.
MrSwiss
Posts: 3631
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: L (l) suffix Bug, not always "Long", WIN-FBC64

Postby MrSwiss » Apr 29, 2018 17:10

@coderJeff, thanks a lot for the Explanations.

This is just a *shorty*, maybe also restating the problem, *in a nutshell*:

Concens mainly: FBC 64 (since, Integer in FBC 32 is a 32bit type).
The Universal Type, I've tried to program, doesn't ever have a consistent 32bit
data-type, because of the inability to use negative literals (data-type forcing).
(working with positive/negative: literals alike, needed for initialization!)
I'm using overloaded initializes, for that ...
The only two suffixes, that are really affected are: 'l' (&) and 'll' and not at all,
the unsigned equivalents ... (since, they are anyway *positive* only!).

Impressive tests you've done, so far ... (I happen to think, a really worthwile effort).

Sorry about the nonsense statement, it was anyway, more aimed at C, than FB!
coderJeff
Site Admin
Posts: 3342
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: L (l) suffix Bug, not always "Long", WIN-FBC64

Postby coderJeff » Apr 29, 2018 17:53

The listing showing after bugfix-879 I posted is same output on fbc-64bit also, so it's consistent between 32bit and 64bit. First impression is that it doesn't seem consistent with itself. It's a low level change to how fbc interprets source code, so concerned about what might break...

The work around in current fbc (which maybe you already know), for negative literals:
You can use negative literals of a specific type, but only by wrapping in a conversion function, for example CLNG(-1), to force the data type as you mention. For example:

Code: Select all

'' 32 or 64 bit
const c = clng(-1)
#define d clng(-1)

#print typeof( c )         '' long
#print typeof( d )         '' long
#print typeof( clng(-1) )  '' long

Even though I say "conversion function", it does result in a non-modifiable constant of a specific data type. Same for (u)byte and (u)short data types which don't have suffix specifier; need to wrap in cbyte/cubyte/short/cushort to get a "literal" constant of the specified type.

Here's some food for thought; either:
- it's impossible to specify a literal byte value in fbc, or,
- a byte value of 65 is expressed literally as cbyte(65)
:)
MrSwiss
Posts: 3631
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: L (l) suffix Bug, not always "Long", WIN-FBC64

Postby MrSwiss » Apr 29, 2018 18:07

<grin> There is, of course, also a different working method:
assign value to a specified variable, then use that, as init(variable 'containing value').
However, this sort of *defeats* the purpose, of the Universal Type.

That's actually, a tested method, for the mentioned: [u]byte / [u]short types ...

The conversions for initial assignment, are probably the better method (currently).
cbruce
Posts: 136
Joined: Sep 12, 2007 19:13
Location: Dallas, Texas

Re: L (l) suffix Bug, not always "Long", WIN-FBC64

Postby cbruce » May 01, 2018 2:38

.
Hmmm... How to fix the issues may be an even bigger task than you thought coderJeff... these folks have done it... but *WOW*!

Interesting reading.

ACCU :: Correct Integer Operations with Minimal Runtime Penalties
https://accu.org/index.php/articles/2344

-------------------------------
Solution:

This library implements special versions of int, unsigned, etc. which behave exactly like the original ones except that the results of these operations are guaranteed to be either arithmetically correct or invoke an error. This will permit one to write arithmetic expressions that cannot produce an erroneous result. Instead, one and only one of the following is guaranteed to occur.

    the expression will yield the correct mathematical result
    the expression will emit a compilation error.
    the expression will invoke a runtime exception.
In other words, the library absolutely guarantees that no arithmetic expression will yield incorrect results.
----------------------------------

It's *just* a C++ header library... but it comes with a little overhead...
----------------------------------
Requirements:

This library is composed entirely of C++ Headers. It requires a compiler compatible with the C++14 standard.

The following Boost Libraries must be installed in order to use this library

    MPL
    Integer
    Config
    Concept Checking
    Tribool
    Enable_if
The Safe Numerics library is delivered with an exhaustive suite of test programs. Users who choose to run this test suite will also need to install the Boost.Preprocessor library.
----------------------------------
.
coderJeff
Site Admin
Posts: 3342
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: L (l) suffix Bug, not always "Long", WIN-FBC64

Postby coderJeff » May 06, 2018 0:38

@cbruce, heh, I look at the first "problem" example on that page, and I think, yup, looks good to me!

I think it would be easier to create a safe type library using an "unsafe" language like FreeBASIC, rather than the other way around, creating unsafe capabilities natively in an completely safe language.

I suppose initially, fbc was all about getting something better working. Fast 32bit compiler to make fast 32bit code, compared to the 16-bit QB we were coming from at the time. There are some things about FreeBASIC that are C like (or Java like if you prefer, e.g. primitive int type), not because it imitates C, but because trying to solve some similar kind of problems.

The only basics other than FB, I have worked with are QB and VB. I suppose they are safer that they could catch many math calculation problems. However, often I would write code in "unsafe" ASM or C and make in to a quicklib or DLL because it was just too cumbersome to do it plain QB/VB.

Thanks for sharing the link.

Return to “General”

Who is online

Users browsing this forum: No registered users and 3 guests