Can I prevent pointer use in this case?

General FreeBASIC programming questions.
Post Reply
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Can I prevent pointer use in this case?

Post by badidea »

Hello all, in the code below, B_type works as wanted. But can it be done without using pointers?
Or how to modify A_type so that it works as B_type?

Code: Select all

type big_type
	dim as integer number(999)
end type

'Option A

type A_type
	dim as big_type big
	declare constructor(byref big as big_type)
end type

constructor A_type(byref big as big_type)
	this.big = big '<-- makes a full copy of big
end constructor

'Option B

type B_type
	dim as big_type ptr pBig
	declare constructor(pBig as big_type ptr)
end type

constructor B_type(pBig as big_type ptr)
	this.pBig = pBig '<-- does not make copy
end constructor

'use it

dim as big_type big
big.number(3) = 111

var A = A_type(big)
var B = B_type(@big)

print A.big.number(3)
print B.pBig->number(3)
print

big.number(3) = 555 'change

print A.big.number(3), "<-- Not changed because a copy was made"
print B.pBig->number(3)
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Can I prevent pointer use in this case?

Post by dodicat »

You could declare A byref and load big into it (via a cast)
or
you could call the constructor after big has been changed (as C)

There are maybe a million easier ways to do it.

Code: Select all

 



type big_type
   dim as integer number(999)
end type

'Option A

type A_type
   dim as big_type big
   declare constructor(byref big as big_type)
  
end type


constructor A_type(byref big as big_type)
   this.big = big '<-- makes a full copy of big
end constructor


'Option B

type B_type
   dim as big_type ptr pBig
   declare constructor(pBig as big_type ptr)
end type

constructor B_type(pBig as big_type ptr)
   this.pBig = pBig '<-- does not make copy
end constructor

'use it

dim as big_type big
big.number(3) = 111


var byref A =*cptr(A_type ptr,@big) 'load A (no constructors used)
var B = B_type(@big)

var C=A_type(big)



print A.big.number(3)
print B.pBig->number(3)
print

big.number(3) = 555 'change




print A.big.number(3), "<-- Not changed because a copy was made (previously)"
print B.pBig->number(3)
print
C.constructor(big) 'easier way
print C.big.number(3)
sleep

 
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Can I prevent pointer use in this case?

Post by fxm »

A little longer, but compatible solution for adding other fields anywhere in 'X_type' (by emulating a reference as a non-static member):

Code: Select all

type big_type
   dim as integer number(999)
end type

'Option A

type A_type
   dim as big_type big
   declare constructor(byref big as big_type)
end type

constructor A_type(byref big as big_type)
   this.big = big '<-- makes a full copy of big
end constructor

'Option B

type B_type
   dim as big_type ptr pBig
   declare constructor(byval pBig as big_type ptr)
end type

constructor B_type(byval pBig as big_type ptr)
   this.pBig = pBig '<-- does not make copy
end constructor

'Option C

type C_type
   declare property rBig () byref as big_type
   declare constructor(byref big as big_type)
   private:
      dim as big_type ptr pBig
end type

property C_type.rBig () byref as big_type
   return *pBig '<-- does not make copy
end property

constructor C_type(byref big as big_type)
   this.pBig = @big '<-- does not make copy
end constructor

'use it

dim as big_type big
big.number(3) = 111

var A = A_type(big)
var B = B_type(@big)
var C = C_type(big)

print A.big.number(3)
print B.pBig->number(3)
print C.rBig.number(3)
print

big.number(3) = 555 'change

print A.big.number(3), "<-- Not changed because a copy was made"
print B.pBig->number(3)
print C.rBig.number(3)
Last edited by fxm on Oct 13, 2018 12:06, edited 1 time in total.
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Can I prevent pointer use in this case?

Post by badidea »

I don't like the 2 suggestions.
* Dodicat's version requires to copy the array (big) everything I change it.
* Fxm's version hides the pointer externally, but it this is a pointer internally. Plus additional lines of code.

Background:
I have two classes again, where one needs information from the other. I don't want to supply this information as arguments.
I'll stick with type_B (with pointer) for now. Maybe, I'll change things later anyway.

For my next project, I'll try code without any class (only structs). Lets say "back to basics". Curious how that will go.
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Can I prevent pointer use in this case?

Post by dodicat »

Hi badidea.
But what does:
"without any class (only structs)"
mean?
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Can I prevent pointer use in this case?

Post by paul doe »

badidea wrote:Background:
I have two classes again, where one needs information from the other. I don't want to supply this information as arguments.
I'll stick with type_B (with pointer) for now. Maybe, I'll change things later anyway.
That's the entire point of encapsulation: no class should depend on specific information (read: details) from another (even less if it's private). Classes should provide functionality, not data. It smacks to me that 'big_type' is going to be used as a Service Locator, am I correct? If that's the case, it makes sense to lay it out as a Monostate:

Code: Select all

type big_type extends Object '' because the type is, indeed, empty
  public:
    declare constructor()
    declare constructor( _
      byval as uinteger )
    declare destructor()
    
    declare property number( _
      byval as integer ) as integer
    declare property number( _
      byval as integer, _
      byval as integer )
  
  private:
    static m_number( any ) as integer
end type

dim as integer big_type.m_number( any )

constructor big_type()
  '' Use the default constructor to create a reference
end constructor

constructor big_type( _
  byval size as uinteger )
  
  '' And use this constructor to instantiate it anew  
  redim m_number( 0 to iif( size < 1, 1, size ) )
end constructor

destructor big_type()
  /'
    The m_number array doesn't get destroyed when the
    instance is deleted, since it's static. It will be
    released at program end.
  '/
end destructor

property big_type.number( _
  byval index as integer ) as integer
  
  return m_number( index )
end property

property big_type.number( _
  byval index as integer, _
  byval value as integer )
  
  m_number( index ) = value
end property

'Option A

type A_type
   dim as big_type big
   declare constructor()
end type

constructor A_type()
end constructor

'Option B

type B_type
   dim as big_type ptr pBig
   declare constructor( byval as big_type ptr )
end type

constructor B_type( byval aBig as big_type ptr )
  pBig = aBig
end constructor

'use it

var big = big_type( 999 )
big.number(3) = 111

var A = A_type()
var B = B_type( @big )

print A.big.number(3)
print B.pBig->number(3)
print

big.number(3) = 555 'change

print A.big.number(3), "<-- Changed because both A and B types use the <same> instance of the *data*"
print B.pBig->number(3)

sleep()
Another consideration: what is the relationship between two classes? Does one needs the other to work altogether, or does it need the other to provide functionality/properties for a specific task? This will determine how you'll handle the dependency. Also, why do you want to 'prevent' pointer usage?
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Can I prevent pointer use in this case?

Post by fxm »

At a given time, if all 'X_type' instances refer to the same 'big_type' instance, a static reference to this can be used as data field of 'X_type':

Code: Select all

type big_type
   dim as integer number(999)
end type

'Option A

type A_type
   dim as big_type big
   declare constructor(byref big as big_type)
end type

constructor A_type(byref big as big_type)
   this.big = big '<-- makes a full copy of big
end constructor

'Option B

type B_type
   dim as big_type ptr pBig
   declare constructor(byval pBig as big_type ptr)
end type

constructor B_type(byval pBig as big_type ptr)
   this.pBig = pBig '<-- does not make copy
end constructor

'Option C

type C_type extends object '<-- just to avoid to declare a useless non static data field
   static byref as big_type big
   declare constructor(byref big as big_type)
end type
dim byref as big_type C_type.big = *Cptr(big_type ptr, 0) '<-- initialization to a "null" variable

constructor C_type(byref big as big_type)
   @this.big = @big '<-- does not make copy ('this.' and not 'C_type.' usage as workaround to bug report #645)
end constructor

'use it

dim as big_type big
big.number(3) = 111

var A = A_type(big)
var B = B_type(@big)
var C = C_type(big)

print A.big.number(3)
print B.pBig->number(3)
print C.big.number(3)
print

big.number(3) = 555 'change

print A.big.number(3), "<-- Not changed because a copy was made"
print B.pBig->number(3)
print C.big.number(3)
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Can I prevent pointer use in this case?

Post by dodicat »

I get an error fxm
Compiler output:
Aborting due to runtime error 12 ("segmentation violation" signal)

A simplification for a control array.

Code: Select all




dim shared as integer number(999)

function dumb(k as integer)  as integer
    function= number(k)
end function

type A_type
      as function(as integer) as integer number= @dumb
end type


dim as A_type A

number(3)=555
print a.number(3)

number(3)=111
print a.number(3)


dim as A_type anyother

print anyother.number(3)

if a.number(20)<>13 then number(20)=13
print a.number(20)


sleep



  
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Can I prevent pointer use in this case?

Post by fxm »

Yes, a compiler bug now fixed in the 1.06 version:
- #822, #814, #842: Compiler crash when initializing static/shared reference (DIM SHARED/STATIC BYREF) with non-constant initializer (e.g. another reference, or dynamic array element)
(precisely from #822: Compiler aborts when initializing a static byref member UDT with a local instance)

Annoying workaround:

Code: Select all

type big_type
   dim as integer number(999)
end type

'Option A

type A_type
   dim as big_type big
   declare constructor(byref big as big_type)
end type

constructor A_type(byref big as big_type)
   this.big = big '<-- makes a full copy of big
end constructor

'Option B

type B_type
   dim as big_type ptr pBig
   declare constructor(byval pBig as big_type ptr)
end type

constructor B_type(byval pBig as big_type ptr)
   this.pBig = pBig '<-- does not make copy
end constructor

'Option C

type C_type extends object '<-- just to avoid to declare a useless non static data field
   static byref as big_type big
   declare constructor(byref big as big_type)
end type
dim shared as big_type big0
dim byref as big_type C_type.big = big0

constructor C_type(byref big as big_type)
   @this.big = @big '<-- does not make copy ('this.' and not 'C_type.' usage as workaround to bug report #645)
end constructor

'use it

dim as big_type big
big.number(3) = 111

var A = A_type(big)
var B = B_type(@big)
var C = C_type(big)

print A.big.number(3)
print B.pBig->number(3)
print C.big.number(3)
print

big.number(3) = 555 'change

print A.big.number(3), "<-- Not changed because a copy was made"
print B.pBig->number(3)
print C.big.number(3)
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Can I prevent pointer use in this case?

Post by badidea »

paul doe wrote:It smacks to me that 'big_type' is going to be used as a Service Locator, am I correct?
I don't know. 'big_type' is actually 'board_type' which contains a 2d array representing the board in a game.
paul doe wrote:Another consideration: what is the relationship between two classes? Does one needs the other to work altogether, or does it need the other to provide functionality/properties for a specific task? This will determine how you'll handle the dependency.
The other 'type' is actually 'piece_type' which defines one tetris piece. One tetris consists of 4 'squares'. To place the piece on the board, I have a function piece_type.possible(). This checks if there is room on the board to place the piece. Other information that the 'board_type' contains if the size of the grid, which is needed in piece_type.draw().
paul doe wrote:Also, why do you want to 'prevent' pointer usage?
A pointer is ok, but I did not like the syntax '->' and '@" and "[ ]". Also higher risk of reading/writing at the wrong memory location I think. I was hope for a simple alternative.
fxm wrote:static byref as big_type big
'Dim as byref' was actually the thing I was looking for. Using it does not seem very straightforward however.
dodicat wrote:dim shared as integer number(999)
'dim shared' is the easy solution. I did not want to use 'dim shared', but I am giving 'piece_type' full access the the 'board_type' anyway with my pointer. Small step to give my whole program access to the game board.
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Can I prevent pointer use in this case?

Post by dodicat »

Dim shared is not required.
You could make everything very private.

Code: Select all

 

namespace  Control
dim as integer number(999)
function dumb(k as integer) as integer
    function= number(k)
end function
end namespace

type A_type
as function(as integer) as integer number= @control.dumb
end type


var A=A_type

Control.number(3)=555
print "a.number(3) = ";a.number(3)

Control.number(3)=111
print "a.number(3) = ";a.number(3)


dim as A_type anyother

print "anyother.number(3) = ";anyother.number(3)

if a.number(20)<>13 then Control.number(20)=13
print "a.number(20) = ";a.number(20)

print
print

sleep

   
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Can I prevent pointer use in this case?

Post by fxm »

A variable declared inside a namespace is always implicitly static and visible throughout the entire program even if the declaration modifier Shared is not specified (static and shared are optional, but this may improve code readability).
Post Reply