Dim Byref syntax

General discussion for topics related to the FreeBASIC project or its community.
Post Reply
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Dim Byref syntax

Post by fxm »

@Admin,
Have you seen my today comment on the "#842 BYREF (variable) does not report some assignment errors detectable on its internal pointer" bug report, which you just have to close ?
coderJeff
Site Admin
Posts: 4326
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Dim Byref syntax

Post by coderJeff »

In both cases, even though we start with `I as Const Integer`, the pointer types are explicitly being manipulated with a CAST, so keep that in mind.

Code: Select all

Static As Const Integer I = 123

'' CASE 1, with BYREF: no error
Static Byref As Integer RI = *Cast(Integer Ptr, @I)
Print RI

'' CASE 2, with POINTER, error
Static As Integer Ptr pI = Cast(Integer Ptr, @I)
Print *pI
CASE 1: Pointer details are hidden. I is CONST integer, but, CAST will cast away the CONST-ness, * operator will dereference, and because it is a BYREF variable, the address is implicitly taken and assigned. Result: No error.

CASE 2: Pointer details are exposed. I is CONST integer, but, CAST will cast away the CONST-ness, and the type conversion is not solved out. It's not a constant and can't be an initializer. Result: Error.
coderJeff
Site Admin
Posts: 4326
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Dim Byref syntax

Post by coderJeff »

fxm wrote:More simply/generally, the following code is not allowed:

Code: Select all

Static As Integer I = 0
Static As Integer J = I
I know, not quite the same, but this should work with next pull request https://github.com/freebasic/fbc/pull/89

Code: Select all

dim shared a as integer = 5
dim shared byref b as integer = a
static byref As integer c = b
dim byref d as integer = c

print a, hex( @a )
print b, hex( @b )
print c, hex( @c )
print d, hex( @d )
My implementation is a little hack-ish, so I expect there to be some time to improve it before it is merged in. You can see the test of what it's supposed to support byref-init-from-byref.bas
coderJeff
Site Admin
Posts: 4326
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Dim Byref syntax

Post by coderJeff »

fxm wrote:@Admin,
Have you seen my today comment on the "#842 BYREF (variable) does not report some assignment errors detectable on its internal pointer" bug report, which you just have to close ?
I closed it because I thought primary bug was fixed, no more segfaults.

I expanded one of the tests you wrote in this forum.

Code: Select all

type X extends OBJECT
   static as const integer y
   static as integer z
end type

dim as const integer X.y = 123
dim as integer X.z = 456

function cbv1() byref as const integer static
      var byref u = X.y
      return u
end function

function cbp1() byref as const integer static
      var byref u = *cast(integer ptr, @X.y)
      return u
end function

function cbp2() byref as const integer static
      var byref u = *cast(const integer ptr, @X.y)
      return u
end function

function cbp3() byref as const integer static
      var byref u = *cast(integer const ptr, @X.y)
      return u
end function

function cbp4() byref as const integer static
      var byref u = *cast(const integer const ptr, @X.y)
      return u
end function

function cpp1() byref as const integer static
      var pu = cast(integer ptr, @X.y)
      return *pu
end function

function cpp2() byref as const integer static
      var pu = cast(const integer ptr, @X.y)
      return *pu
end function

function cpp3() byref as const integer static
      var pu = cast(integer const ptr, @X.y)
      return *pu
end function

function cpp4() byref as const integer static
      var pu = cast(const integer const ptr, @X.y)
      return *pu
end function

function bv1() byref as const integer static
      var byref u = X.z
      return u
end function

function bp1() byref as const integer static
      var byref u = *cast(integer ptr, @X.z)
      return u
end function

function bp2() byref as const integer static
      var byref u = *cast(const integer ptr, @X.z)
      return u
end function

function bp3() byref as const integer static
      var byref u = *cast(integer const ptr, @X.z)
      return u
end function

function bp4() byref as const integer static
      var byref u = *cast(const integer const ptr, @X.z)
      return u
end function

function pp1() byref as const integer static
      var pu = cast(integer ptr, @X.z)
      return *pu
end function

function pp2() byref as const integer static
      var pu = cast(const integer ptr, @X.z)
      return *pu
end function

function pp3() byref as const integer static
      var pu = cast(integer const ptr, @X.z)
      return *pu
end function

function pp4() byref as const integer static
      var pu = cast(const integer const ptr, @X.z)
      return *pu
end function

? cbv1()
? cbp1(), cbp2(), cbp3(), cbp4()
? cpp1(), cpp2(), cpp3(), cpp4()

? bv1()
? bp1(), bp2(), bp3(), bp4()
? pp1(), pp2(), pp3(), pp4()
Different results depending on -exx or not. If you subscribe to fbc project sourceforge.net you probably already seen the continued discussion on the closed bug report 842.

There could be multiple bugs here. I don't know. Currently BYREF succeeds where POINTER versions do not, except in -exx, they are both same.
coderJeff
Site Admin
Posts: 4326
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Dim Byref syntax

Post by coderJeff »

Since last post in this topic on Jun 22, I have been working on bugs related to the closed #842, which kind of started it all. My efforts are currently in pull request 90.

I've made my way through the following:
#642 Pointer casting allows constness dropping
#886 Inconsistent error with BYREF and CAST on CONST variables
#801 parser allows more constructs under -exx than without it
#727 RTL functions not checking Constness unless marked RTL_CONST
#880 Overload binary operators do not support covariant arguments

Currently testing overload resolution. I posted here because of the indirect relation to this thread and they are all related to each other. Plus the discussions are somewhat fragmented. If anyone knows of discussions that are related to any of these bugs, please update the sf.net ticket, and I could continue discussion in the individual forum topics.
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: Dim Byref syntax

Post by Munair »

Should it possible to return a null reference without resorting to an explicit cast overload (if that is possible):

Code: Select all

type tt extends object
	s as string
end type

function NewTT(s as string) as tt
	dim res as tt
	if len(s) then
		res.s = s
		return res
	end if
	return *cptr(tt ptr, 0)
end function

dim t as tt

t = NewTT("hello")
if t <> 0 then ' not possible and member access raises segmetation fault
	print "assigned"
else
	print "nil"
end if
St_W
Posts: 1626
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Dim Byref syntax

Post by St_W »

I don't think that you can do that without using pointers explicitly. I would even have expected the application to crash when you "return *cptr(tt ptr, 0)", because you're returning an object. And this object is constructed from the dereferenced null reference, which should call the copy constructor of "tt". Maybe you're just lucky or maybe it's fine, I can't tell (at least not without deeper investigation). But I'd not use such code, but simply use pointers instead.

//edit: Wikipedia (https://en.wikipedia.org/wiki/Reference_(C%2B%2B)) says the following about references in C++ (and it's probably the same in FB):
Wikipedia wrote:A reference shall be initialized to refer to a valid object or function. [Note: in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the "object" obtained by dereferencing a null pointer, which causes undefined behavior. [...] ]
So it's an error no matter whether you return the object by value or as a reference, because you're dereferencing a null pointer either way.
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Dim Byref syntax

Post by fxm »

Indeed in this case, using a reference is more complex than directly a pointer:

Code: Select all

type tt extends object
   s as string
end type

function NewTT(byref s as string) byref as tt
   if len(s) then
      dim byref as tt res = *new tt
      res.s = s
      return res
   end if
   return *cptr(tt ptr, 0)
end function

dim byref as tt t = *cptr(tt ptr, 0)

@t = @(NewTT("hello"))
if @t <> 0 then
   print "assigned"
else
   print "nil"
end if
delete @t

@t = @(NewTT(""))
if @t <> 0 then
   print "assigned"
else
   print "nil"
end if
delete @t

sleep
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: Dim Byref syntax

Post by Munair »

St_W wrote:I would even have expected the application to crash when you "return *cptr(tt ptr, 0)"
fxm wrote:Presently, a reference can also be re-initialized to refer to nothing, a "null" reference (@ref = 0), and this can be done even at the level of its declaration
and
fxm wrote: Presently one can also pass/return to/from a procedure a "null" reference by using '*Cptr(datatype Ptr, 0)', or even the short-cut syntax 'Byval 0'.
It's just that I prefer to use references as much as possible for my project, which should have easy access by default for novice programmers.
St_W
Posts: 1626
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Dim Byref syntax

Post by St_W »

Thanks for the example fxm, I was wrong evidently.

I had a look at the C code generated by the C emitter of FB for both return *cptr(tt ptr, 0) (with a byref return value) and dim byref as tt t = *cptr(tt ptr, 0). The generated code assigns the null pointer to the reference and does not try to dereference a null value (like if you had not declared it as byref). So the generated application is valid, despite the syntax suggesting otherwise.

Just as a (non-FB) sidenote: I recently read that the upcoming C# 8.0 release includes a new optional feature that will require to mark references as nullable if you want to assign null values to them (previously that was possible without any warnings). IMHO that's a nice solution for avoiding errors on one side and still allowing null references on the other side. If you're interested, here's the article: https://blogs.msdn.microsoft.com/dotnet ... ing-c-8-0/

//edit: Also note that you need to be extremely careful so that you do not dereference the null reference by accident. For example the copy constructor is called when you'd just write t = NewTT("") instead of @t = @(NewTT("")) in fxm's example. So I'd still suggest to use pointers explicitly if you need to deal with null references.
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: Dim Byref syntax

Post by Munair »

The implementation of a nil object would be great, something like:

Code: Select all

dim t as tt ' type declared but no instance yet
t = new tt() ' new instance

' or

t = FuncTT()
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Dim Byref syntax

Post by fxm »

In a previous post, I proposed to authorize the syntax declaration of reference without initializer (for defining a null reference):
Dim Byref t As tt
equivalent to:
Dim Byref t As tt = *Cptr(tt Ptr, 0)

In all case, a reference can be reinitialized to point on an other object by:
@t = @object
(in particular, '@t = 0' allows to retrieve a null reference)
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: Dim Byref syntax

Post by Munair »

fxm wrote:In a previous post, I proposed to authorize the syntax declaration of reference without initializer (for defining a null reference):
Dim Byref t As tt
equivalent to:
Dim Byref t As tt = *Cptr(tt Ptr, 0)
Yes, that would be something. I generally don't like the immediate creation of the object of which a different copy would have to be made later on.
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: Dim Byref syntax

Post by Munair »

Currently perhaps some obfuscation might be achieved:

Code: Select all

#define init(o) *cptr(o ptr, 0)
#define nil(o) @(o) = 0

type tt extends object
	s as string
end type

function NewTT(s as string) byref as tt
	if len(s) then
		dim byref res as tt = *new tt()
		res.s = s
		return res
	end if
	return *cptr(tt ptr, 0)
end function

dim byref t as tt = init(tt)

@t = @(NewTT(""))
if not nil(t) then
	print t.s
	delete @t
else
	print "no ref"
end if
Last edited by Munair on Nov 26, 2018 16:10, edited 1 time in total.
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: Dim Byref syntax

Post by Munair »

Or, to make it really fancy:

Code: Select all

#define Init(o) *cptr(o ptr, 0)
#define Nil(o) @(o) = 0
#define Obj(o) byref o
#define Ref(o) @(o)

type tt extends object
	s as string
end type

function NewTT(s as string) byref as tt
	if len(s) then
		dim Obj(res) as tt = *new tt()
		res.s = s
		return res
	end if
	return Init(tt)
end function

dim Obj(t) as tt = Init(tt)

Ref(t) = Ref(NewTT(""))
if not Nil(t) then
	print t.s
	delete Ref(t)
else
	print "no ref"
end if
It might be over the top, but it shows in a clear manner what is happening.
Last edited by Munair on Nov 26, 2018 16:23, edited 2 times in total.
Post Reply