FPC - wasted memory... 
Author Message
 FPC - wasted memory...

{$MODE OBJFPC}

type TValue=longint; // of course it should be some complex type or a
pointer

const listsize=32;

type
      TSomeFactory=class;

      TSomething = class//(sometype)
        private
          parent:TSomeFactory;
          listindex:longint;
        public
          value:TValue;
          constructor Create(a:TValue; parnt:TSomeFactory);
          destructor Destroy;
          function GetParent:TSomeFactory;
          procedure SetPersistant;
          procedure SetVolatile;
          function IsPersistant:boolean;
          function GetIndex:longint;
          function add(a:TSomething):TValue;
        end;

      TSomeFactory=class
      private
        lastindex:longint;
        list:array[1..listsize] of TSomething;
      public
        constructor Create;
        function Something(a:TValue):TSomething;
        function AddToList(thing:TSomething):longint;
        procedure RemoveFromList(thing:TSomething);
        procedure Purge;
      end;

constructor TSomeFactory.Create;
var i:longint;
begin
  for i:=1 to listsize do list[i]:=nil;
end;

function TSomeFactory.AddToList(thing:TSomething):longint;
var i:longint;
begin
  i:=0;
  repeat inc(i) until (i>listsize) or (list[i]=nil);
  if i>listsize then
  begin
    writeln('TSomeFactory.AddToList: list is full');
    halt;
  end;
  list[i]:=thing;
  AddToList:=i;
end;

procedure TSomeFactory.RemoveFromList(thing:TSomething);
begin
  list[thing.GetIndex]:=nil;
end;

function TSomeFactory.Something(a:TValue):TSomething;
begin
  Something:=TSomething.Create(a,self);
end;

procedure TSomeFactory.Purge;
var i:longint;
begin
  for i:=1 to listsize do
    if list[i]<>nil then list[i].Destroy;
end;

constructor TSomething.Create(a:TValue; parnt:TSomeFactory);
begin
  { if value is a pointer, allocate it here }
  value:=a;
  parent:=parnt;
  listindex:=0;
  SetVolatile;
end;

destructor TSomething.Destroy;
begin
  { if value is a pointer, destroy it here }
end;

function TSomething.GetParent:TSomeFactory;
begin
  GetParent:=parent;
end;

function TSomething.GetIndex:longint;
begin
  GetIndex:=listindex;
end;

function TSomething.IsPersistant:boolean;
begin
  IsPersistant:=listindex=0;
end;

procedure TSomething.SetPersistant;
begin
  if IsPersistant then exit;
  parent.RemoveFromList(self);
  listindex:=0;
end;

procedure TSomething.SetVolatile;
begin
  if not IsPersistant then exit;
  listindex:=parent.AddToList(self);
end;

function TSomething.Add(a:TSomething):TValue;
begin
  Add:=self.value+a.value;
end;

operator + (a,b:TSomething):TSomething;
begin
  result:=a.GetParent.Something(a.Add(b));
end;

var factory : TSomeFactory;
     a,b,c  : TSomething;

begin
  factory:=tsomefactory.create();
  writeln('free memory with no TSomething variables = ',memavail);
  a:=factory.something(9);
  writeln('free memory with  1 TSomething variable  = ',memavail);
  b:=factory.something(10);
  c:=a+b+factory.something(11);
  writeln('free memory after calcuations            = ',memavail);
  c.setpersistant;
  factory.purge;
  writeln('free memory with  1 TSomething variable  = ',memavail);
  writeln('value of c = ',c.value);
  factory.destroy;
end.

--
Azarien

[delete the letter v from my e-mail address]



Thu, 15 Dec 2005 22:43:11 GMT  
 FPC - wasted memory...
bugfix:

procedure TSomeFactory.Purge;
var i:longint;
begin
  for i:=1 to listsize do
    if list[i]<>nil then
    begin
      list[i].Destroy;
      list[i]:=nil;    // here
    end;
end;



Fri, 16 Dec 2005 03:59:42 GMT  
 FPC - wasted memory...

Quote:

> bugfix:

> procedure TSomeFactory.Purge;
> var i:longint;
> begin
>   for i:=1 to listsize do
>     if list[i]<>nil then
>     begin
>       list[i].Destroy;
>       list[i]:=nil;    // here
>     end;
> end;

To make it totally memory neutral, the result also has to be freed as last
statement. (use -ghl to get an idea)


Fri, 16 Dec 2005 05:13:41 GMT  
 FPC - wasted memory...
Okay,work....but you will have more problems. %-(

IMHO, classes generally aren't compatible with overloading because
for example,"+" operator is a (formally) method for 2 objects
(here and later i  will say "object" for object in general("classes"
too), and "pointer to record" for what you define with "class"
keyword)

If you have many types like complex numbers,vectors,matrixes,complex
matrixes,qaternions (q matrices),tensors,....(a lot of types,it's not
so non-realistic if one are working on symbolic math),
how "+" will select right procedure for 2 operands at runtime(both
operands are pointers to record) ?
(imho,if you don't need to select procedure runtime,you don't need
classes)

I solved similar problem of procedure overloading  via

Procedure{or function} DoSomething(a,b:TsomeParentClass);
begin
if a is TSomeCompatibleChild then begin
 if b is TSomeCompatibleChild then begin{a and b is
Tsomecompatiblechild}
  ......
 end else begin{a is Tsomecompatiblechild,b is not}
  .....
 end;
end else begin
 if b is SomeCompatibleChild then begin {a is not
Tsomecompatiblechild,b is}
  ......
 end else begin {a and b is not Tsomecompatiblechild}
  .....
 end;
end;

end;

but it's not the "build-in object-oriented approarch":

it's like(if not the same as) "good old object model in standard
Pascal"
(
"case a.WhatIsIt of
IsParent:..
isChild:..
end;" .
)
,so,for myself, i'm using records for any math data.

Regards,
Good luck with this crazy(imho) overloading,

Dmytry.

http://dmytrylavrov.narod.ru



Fri, 16 Dec 2005 05:27:10 GMT  
 FPC - wasted memory...

Quote:
> Okay,work....

still needs some bugfixing ;-)

Quote:
> but you will have more problems. %-(

<CUT>

Quote:
> but it's not the "build-in object-oriented approarch":
> it's like(if not the same as) "good old object model in standard
> pascal"

<CUT>

I don't understand your problem...
If you found a working solution, what's still the matter? ;-)

BTW.
I've implemented factories in my not-yet-done matrices unit, and it looks
like this:

uses matrices;

var a,b,c:TMatrix;

begin
  a:=Matrix(2,2); { 2x2 matrix; same as TMatrix.CreatePersistant(2,2) }

// the matrix elements are of the type double,
// but it's just the matter of "type matrixtype=any_type_with_operators"

  a[1,1]:=1; a[1,2]:=2;  {  this is the main reason           }
  a[2,1]:=3; a[2,2]:=4;  {  i want TMatrix to be a class :-)  }

  b:=mPersist(mIdent(2));

  { mIdent(2) returns [1,0; 0,1] }
  { mPersist commits SetPersistant method and returns the same pointer as
its parameter }

  writeln(mDet(a*mInv(b)*3))); { memory leak here... mInv(b) is actually
b.inv }

  PurgeMatrices; { ..freed. same as DefaultMatrixFactory.Purge; }

  { a and b have not been destroyed: }

  a.destroy;
  b.destroy;
end.

--
Azarien



Fri, 16 Dec 2005 08:03:02 GMT  
 FPC - wasted memory...

Quote:

> I don't understand your problem...
> If you found a working solution, what's still the matter? ;-)

temp variable is also working soluton....but normal expressions is one
why we call pascal "high-level language".

Problem that it's not extensible without modifing unit sources.If one
modify sources of free unit,one will "lost support"-any time new
version avaliable hi should change sources. (it's problem for "only
myself" too,i does not want to add to everything to one unit that are
used in lot of programs.So,i should have a lot of versions of one
unit... )

Quote:

> BTW.
> I've implemented factories in my not-yet-done matrices unit, and it looks
> like this:

> uses matrices;

> var a,b,c:TMatrix;

> begin
>   a:=Matrix(2,2); { 2x2 matrix; same as TMatrix.CreatePersistant(2,2) }

Your constructor should have "abstract constructor" in params if you
want to implement abstract matrix ops that can contain another
matrixes inside,or complex numbers...or something with ops(if memory
serves it called abel group...or something like it).

Quote:

> // the matrix elements are of the type double,
> // but it's just the matter of "type matrixtype=any_type_with_operators"

>   a[1,1]:=1; a[1,2]:=2;  {  this is the main reason           }
>   a[2,1]:=3; a[2,2]:=4;  {  i want TMatrix to be a class :-)  }

it also was main reason for me...:)
why i can't simply overload []...?(asking my keyboard ;-)

"Pointers to records"(in general) are good for abstraction in math,but
build-in implementation of classes in delphi and pascal does not cover
the problem,and in any case we should use "good-old" methods
selection(with problem that it's not extensible without changing
method-selection procedure).

IMHO,classes was defined mainly for GUI's....because any GUI have a
lot of abstractions.And GUIs typically have methods that can be
selected by only one operand. Math have methods that should be
selected for both operands.(classes based on idea that one operand is
main("self"),and anothers is not...)

Quote:

>   b:=mPersist(mIdent(2));

>   { mIdent(2) returns [1,0; 0,1] }
>   { mPersist commits SetPersistant method and returns the same pointer as
> its parameter }

>   writeln(mDet(a*mInv(b)*3))); { memory leak here... mInv(b) is actually
> b.inv }

>   PurgeMatrices; { ..freed. same as DefaultMatrixFactory.Purge; }

>   { a and b have not been destroyed: }

>   a.destroy;
>   b.destroy;
> end.

In any case,your ":=" will not duplicate matrix,it will only copy the
pointer,and it's uncompatible with "math notation"...and it will cause
a lot of problems-sometime you should use method that return copy of
matrix,sometime if you have pascal temp - shouldnt.
in "c:=a+b" c is copy_of_instance of "a+b"(if you will change c,a+b
will not be changed),and in "c:=a" c is a reference to a,and a will be
changed.

Formally if you use "c:=a+b",and then "c:=something",you should have
"a+b:=something" in result ;-)
What if you have "c:=a+0" or "c:=a*1" ?(for object that allow
"object+real" operation)
a+0 not more equal to a  and a*1....(i don't mean "=" returns false",i
mean unequal for simplifications)

--------------------------------------important
idea----------------------
You can solve it(and temp problems!) if overloaded operator destroys
both of operands,
and use "c:=(a.newinstance+b.newinstance)" notation,that's formally
correct.But it's looks strange,and more crazy.

-------
Maybe,it's possible to implement memory deallocation in another
way,similar to ansistrings:
add "refcount" variable to your root class,
Overload ":=" for this class,
when assign one more reference,increment refcount of what you assign
to,decriment for what was unassigned,
when refcount=0,add class to linked list,

and on iddle or when "heap error" occus,deallocate all from this list.

p.s.
i'm still thinking that LISP is first and last truly object-oriented
language.
Anything is a list or atom,and list is a object with dynamic method
selection.

(but lisp is too SLOOOOOW).



Fri, 16 Dec 2005 17:02:30 GMT  
 FPC - wasted memory...

Quote:
> > uses matrices;

> > var a,b,c:TMatrix;

> > begin
> >   a:=Matrix(2,2); { 2x2 matrix; same as TMatrix.CreatePersistant(2,2) }

> Your constructor should have "abstract constructor" in params if you
> want to implement abstract matrix ops that can contain another
> matrixes inside,or complex numbers...or something with ops(if memory
> serves it called abel group...or something like it).

I thought about this, but at this point I'm working on matrices, not the
whole algebra...

Quote:

> > // the matrix elements are of the type double,
> > // but it's just the matter of "type matrixtype=any_type_with_operators"

> >   a[1,1]:=1; a[1,2]:=2;  {  this is the main reason           }
> >   a[2,1]:=3; a[2,2]:=4;  {  i want TMatrix to be a class :-)  }

> it also was main reason for me...:)
> why i can't simply overload []...?(asking my keyboard ;-)

> "Pointers to records"(in general) are good for abstraction in math,but
> build-in implementation of classes in delphi and pascal does not cover
> the problem,and in any case we should use "good-old" methods
> selection(with problem that it's not extensible without changing
> method-selection procedure).

> IMHO,classes was defined mainly for GUI's....because any GUI have a
> lot of abstractions.And GUIs typically have methods that can be
> selected by only one operand. Math have methods that should be
> selected for both operands.(classes based on idea that one operand is
> main("self"),and anothers is not...)

I put operators outside of class, as well as functions which take two
operands:

operator +(a,b:tmatrix) w:tmatrix;
var i,j:longword;
begin
  if (a.m<>b.m) or (a.n<>b.n) then runerror(207); // invalid operation
  w:=tmatrix.create(a.m,a.n);
  for i:=1 to a.m do
    for j:=1 to a.n do
      w[i,j]:=a[i,j]+b[i,j]; { slow; optimisation needed (direct memory
addessing) }
end;

- Show quoted text -

Quote:

> >   b:=mPersist(mIdent(2));

> >   { mIdent(2) returns [1,0; 0,1] }
> >   { mPersist commits SetPersistant method and returns the same pointer
as
> > its parameter }

> >   writeln(mDet(a*mInv(b)*3))); { memory leak here... mInv(b) is actually
> > b.inv }

> >   PurgeMatrices; { ..freed. same as DefaultMatrixFactory.Purge; }

> >   { a and b have not been destroyed: }

> >   a.destroy;
> >   b.destroy;
> > end.
> In any case,your ":=" will not duplicate matrix,it will only copy the
> pointer,and it's uncompatible with "math notation"...and it will cause
> a lot of problems-sometime you should use method that return copy of
> matrix,sometime if you have pascal temp - shouldnt.
> in "c:=a+b" c is copy_of_instance of "a+b"(if you will change c,a+b
> will not be changed),

in c:=a+b, c should be what became a+b. a+b is a new class instance, created
by the operator.
There's no point in _copying_ it to c. When using "factories" c should be
simply set as persistant. Then a and b should be destroyed if they were
temporary.

Quote:
> and in "c:=a" c is a reference to a,and a will be
> changed.

unfortunately FPC does not allow sametype:=sametype operator,
but it could be workarounded by a function like a:=mCopy(b) or a:=b.copy

Quote:
> Formally if you use "c:=a+b",and then "c:=something",you should have
> "a+b:=something" in result ;-)

You mean that in c:=a+b, if c has already been created, the result of a+b
should be copied into existing c? Or at least the existing c shall be
destroyed...
I think with no :=(a:tmatrix):tmatrix operator it cannot be done.

Quote:
> What if you have "c:=a+0" or "c:=a*1" ?(for object that allow
> "object+real" operation)

You'll get the copy of c.
so c:=a copies only the pointer, but c:=a*1 copies all the data into a new
instance :-)

Quote:
> a+0 not more equal to a  and a*1....(i don't mean "=" returns false",i
> mean unequal for simplifications)

{a+0}'s _data_ will be identical to a's _data_.

operator =(a:tmatrix):tmatrix seems to be not allowed :-(
but mEqual(a,b):boolean works fine (compares all matrix elements)

Quote:
> --------------------------------------important idea----------------------
> You can solve it(and temp problems!) if overloaded operator destroys
> both of operands,
> and use "c:=(a.newinstance+b.newinstance)" notation,that's formally
> correct.But it's looks strange,and more crazy.

And those newinstances shall be destroyed by the operator, right?

Quote:
> Maybe,it's possible to implement memory deallocation in another
> way,similar to ansistrings:

Good idea, but...

Quote:
> Overload ":=" for this class,

this is not possible.

Quote:
> i'm still thinking that LISP is first and last truly object-oriented
> language.
> Anything is a list or atom,and list is a object with dynamic method
> selection.

> (but lisp is too SLOOOOOW).

Let's use plain assembler ;-)

--
Azarien



Fri, 16 Dec 2005 18:44:06 GMT  
 FPC - wasted memory...

Quote:


> : > compare to the (*shudder*) workaround given elsewhere in this thread where
> : > a pointer to released memory is used to access the temp data.

> : Good thinking, I like it! The only problem I can think of is using the same
>                 ^^^^
> : factory in multiple threads.

> I hope that quote above is not about accessing released memory. With
> nested expressions there may be some time between finishing computing
> a subexpression and using the result. If the memory menager is eager
> it may reuse "free" memory and invalidate the result before it is used.

It was about accessing free'd memory :) As I said it was a poor
solution, it is working with c / c++, but I got no idea if this will
ever work in Pascal. Never worked with operator overloading in Pascal,
I think the lack of creating an object (in Pascal you always create a
pointer to an object) is making operator overload pretty impossible (I
don't like the solution with an object list and a garbage collector so
I still haven't seen a Pascal compatible solution I like)...

[I think returning a local variable in c involves pushing it onto the
stack, this is probably why it works so well... Anyway this IS the way
you are doing such things in c, but I know c is not Pascal :o)]

The garbage collector method will work, but imo its no different from
doing the a:=b*c; d:=a+e; a.destroy; thing. It's (imo) a workaround,
not a solution.

/Nic

The whole problem is about writing a memory neutral method that
returns an object you do not give as an input... If someone can do
this, it's a solution. Otherwise it's just a workaround. IMO :o)



Fri, 16 Dec 2005 20:56:02 GMT  
 FPC - wasted memory...

Quote:



> you are doing such things in c, but I know c is not Pascal :o)]

> The garbage collector method will work, but imo its no different from
> doing the a:=b*c; d:=a+e; a.destroy; thing. It's (imo) a workaround,
> not a solution.

Using refcounted interfaces might be a "better" solution. (for 1.1), but I
haven't tried that.

This worked very well for me (and even better in some circumstances)



Fri, 16 Dec 2005 21:40:10 GMT  
 FPC - wasted memory...

Quote:
> > IMHO,classes was defined mainly for GUI's....because any GUI have a
> > lot of abstractions.And GUIs typically have methods that can be
> > selected by only one operand. Math have methods that should be
> > selected for both operands.(classes based on idea that one operand is
> > main("self"),and anothers is not...)

> I put operators outside of class, as well as functions which take two
> operands:

> operator +(a,b:tmatrix) w:tmatrix;
> var i,j:longword;
> begin
>   if (a.m<>b.m) or (a.n<>b.n) then runerror(207); // invalid operation
>   w:=tmatrix.create(a.m,a.n);
>   for i:=1 to a.m do
>     for j:=1 to a.n do
>       w[i,j]:=a[i,j]+b[i,j]; { slow; optimisation needed (direct memory
> addessing) }
> end;

And,so,it can't select right procedure(or method)...It works only if
you have one class with [operator or function or
procedure]overloading.If you have 2 compatible classes,for example,it
will not always will select right procedure,and it's will be very bad
when you will need to extend your unit.

Quote:
> > in "c:=a+b" c is copy_of_instance of "a+b"(if you will change c,a+b
> > will not be changed),

> in c:=a+b, c should be what became a+b. a+b is a new class instance, created
> by the operator.

Yes i'm wrong here.  

Quote:
> There's no point in _copying_ it to c. When using "factories" c should be
> simply set as persistant. Then a and b should be destroyed if they were
> temporary.

> > and in "c:=a" c is a reference to a,and a will be
> > changed.

> unfortunately FPC does not allow sametype:=sametype operator,
> but it could be workarounded by a function like a:=mCopy(b) or a:=b.copy

It's named "a:=b.newinstance"
-newinstance is a method of Tobject

Pascal allows "someclass:=anotherclass" reference assignment operator

Quote:

> > Formally if you use "c:=a+b",and then "c:=something",you should have
> > "a+b:=something" in result ;-)

> You mean that in c:=a+b, if c has already been created, the result of a+b
> should be copied into existing c? Or at least the existing c shall be
> destroyed...
> I think with no :=(a:tmatrix):tmatrix operator it cannot be done.

No,i mean that if all works in "formally correct" way,c became to be
"REFERENCE_TO_EXPRESSION" a+b;if we will change a or b ,c will be
changed.But it does not work right...

(i will explain later)

Quote:
> > What if you have "c:=a+0" or "c:=a*1" ?(for object that allow
> > "object+real" operation)

> You'll get the copy of c.
> so c:=a copies only the pointer, but c:=a*1 copies all the data into a new
> instance :-)

it was ritorical qestion...;)

I mean that c:=a+0 copyes a to c,and c:=a makes reference.So,sometimes
you can't replace a+0 to a, and sometimes can.
It's again uncompatible with math notation.

In "formally designed language" "c:=anyexpression" slould always copy
result,XOR always make reference,depend to meaning of ":=" operator.
Language where ":=" makes reference  should allow only "reference

pascal)at right side of "reference:="
,
XOR if they allow math expressions at right side of "reference:=",they
should have references to math expression like in lisp...
In pascal,'reference:=' seems sometimes to be reference,and sometimes
copy...

Quote:

> > a+0 not more equal to a  and a*1....(i don't mean "=" returns false",i
> > mean unequal for simplifications)

> {a+0}'s _data_ will be identical to a's _data_.

By "unequal for simplifications" i mean that sometimes i can't replace
a+0 by a,and sometimes can.

if i have "b:=a*sqr(sin(alpha))+a*sqr(cos(alpha))",i will replace it
to b:=a,"automatically",without thinking on it. So,specific pascal
"classes" does not covered for final user,and it's more
ununderstandable( :-) than plain assembler for final user if final
user don't familiar with overloading.

What's with a:=(b) ???(i know,it's reference,it's another ritorical
qestion)

Quote:

> operator =(a:tmatrix):tmatrix seems to be not allowed :-(
> but mEqual(a,b):boolean works fine (compares all matrix elements)

> > --------------------------------------important idea----------------------
> > You can solve it(and temp problems!) if overloaded operator destroys
> > both of operands,
> > and use "c:=(a.newinstance+b.newinstance)" notation,that's formally
> > correct.But it's looks strange,and more crazy.

> And those newinstances shall be destroyed by the operator, right?

Yes.

It seems to be "formally right",and seems to solve all problems:

1:you always destroy all temp;
2:you always can replace "b:=a.newinstance*1+0" by "b:=a.newinstance";
3:you may not worry about temps.
-you have allocated unneeded temp/
+you may use instance of one operand to store result.
 +For one param operators/functions(like sqrt or log),it will not make
any unneeded temps.
  +For 2 params operators it will not make more temp that in first
solution

in comparation with previous idea:
in previous approarch,"a+0" can't be freely replaced by "a".

For example
d:=a*(b+c); ==>
d:=a.newinstance*(b.newinstance+c.newinstance);
we destroyed all temps automatically.

- Show quoted text -

Quote:

> > Maybe,it's possible to implement memory deallocation in another
> > way,similar to ansistrings:

> Good idea, but...

> > Overload ":=" for this class,

> this is not possible.

> > i'm still thinking that LISP is first and last truly object-oriented
> > language.
> > Anything is a list or atom,and list is a object with dynamic method
> > selection.

> > (but lisp is too SLOOOOOW).

> Let's use plain assembler ;-)

Heh,in comparation with MathLab,pascal is like plain assembler ;-).()

Summary:
You can solve it(and temp problems!) if overloaded operator destroys
both of operands,
and use "c:=d*(a.newinstance+b.newinstance)" notation,that's formally
correct.But it's looks strange,and more crazy.

You may use one operand to store result,and it will not make more
temp.



Fri, 16 Dec 2005 22:34:38 GMT  
 FPC - wasted memory...

Quote:

> This worked very well for me (and even better in some circumstances)

I meant the factory stuff with "this"


Fri, 16 Dec 2005 23:21:39 GMT  
 
 [ 40 post ]  Go to page: [1] [2] [3]

 Relevant Pages 
 

 
Powered by phpBB® Forum Software