A better way?

classic Classic list List threaded Threaded
34 messages Options
12
Reply | Threaded
Open this post in threaded view
|

A better way?

Ryan Joseph
The most annoying problem I have with Pascal currently is with circular unit dependanices and “global” classes that need to be referenced from many units. In other languages I would make a forward declaration of the class in  one file then implement it in another file so that all files could reference the class. It’s maybe a symptom of a “bad" design but sometimes it’s just faster and easier so it’s a problem I have to fight Pascal to make it work.

When I moved to FPC the solution I started using was this pattern below where I make an abstract class then override the methods I need in the global namespace within in the “main unit”. This is a bad hack to workaround a feature of the language but I wonder if there’s a better way. Does anyone have any ideas I could try?

========

"global” unit shared by many other units:

type
  TSomeClassAbstract = class (TObject)
    procedure DoSomething; virtual; abstract;
  end;
 
“main” unit which implements the class:  
 
type
  TSomeClass = class (TSomeClassAbstract)
    procedure DoSomething; override;
  end;


Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A better way?

Graeme Geldenhuys-6
On 2016-04-14 05:29, Ryan Joseph wrote:
> The most annoying problem I have with Pascal currently is with
> circular unit dependanices and “global”

If you can give an actual example we can help. I've used TP then Delphi
and now Free Pascal for more than 20+ years. I can probably count on one
hand how many circular reference issues I had. So I dont' think it is
such a big problem as you make out.

Often moving uses clause references from the Interface section to the
Implementation section solve the problem. Sometimes using a base class
in the interface works. Sometimes using Interfaces (the language
feature) is a much better approach.

So again, if you can give an actual example of the various units, and
how they relate (use each other), then we might be able to help you further.

Regards,
  Graeme

--
fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/

My public PGP key:  http://tinyurl.com/graeme-pgp
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A better way?

Tony Whyman
In reply to this post by Ryan Joseph
Ryan,

Reading through your post, I hope that you are aware that most circular
dependencies can be avoided by referencing other units from the "uses"
clause in the "implementation" section and keeping the "uses" clauses in
"interfaces" down to those references strictly necessary for the unit's
interface.

Having probably told you something you already know, i do sometimes get
circular reference problems and usually because a program has evolved
rather than having been designed properly. Sometimes it's better just to
take as a hint to structure your program better but, otherwise, the
techniques available are:

1. Abstract classes (as you suggest)

2. Interfaces

3. Dynamic casts.

Of the three, dynamic casts are often the quick and dirty way of fixing
the problem as they can allow you to move a problematic unit reference
from the "interface uses" to the "implementation uses", replacing the
class reference in the unit interface to something generic like
"TObject" and them coercing it to the required class when you actually
use it.

I hope this helps.

Regards

Tony Whyman
MWA

On 14/04/16 05:29, Ryan Joseph wrote:

> The most annoying problem I have with Pascal currently is with circular unit dependanices and “global” classes that need to be referenced from many units. In other languages I would make a forward declaration of the class in  one file then implement it in another file so that all files could reference the class. It’s maybe a symptom of a “bad" design but sometimes it’s just faster and easier so it’s a problem I have to fight Pascal to make it work.
>
> When I moved to FPC the solution I started using was this pattern below where I make an abstract class then override the methods I need in the global namespace within in the “main unit”. This is a bad hack to workaround a feature of the language but I wonder if there’s a better way. Does anyone have any ideas I could try?
>
> ========
>
> "global” unit shared by many other units:
>
> type
>    TSomeClassAbstract = class (TObject)
>      procedure DoSomething; virtual; abstract;
>    end;
>    
> “main” unit which implements the class:
>    
> type
>    TSomeClass = class (TSomeClassAbstract)
>      procedure DoSomething; override;
>    end;
>
>
> Regards,
> Ryan Joseph
>
> _______________________________________________
> fpc-pascal maillist  -  [hidden email]
> http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
>

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A better way?

Ryan Joseph

> On Apr 14, 2016, at 3:02 PM, Tony Whyman <[hidden email]> wrote:
>
> Reading through your post, I hope that you are aware that most circular dependencies can be avoided by referencing other units from the "uses" clause in the "implementation" section and keeping the "uses" clauses in "interfaces" down to those references strictly necessary for the unit's interface.

I had no idea you could declare uses in the implementation! That could probably fix 90% of the problems I’m having which I’ve used abstract classes, dynamic method invocation and more recently interfaces to workaround. Don’t tell me this has been around for 20 years now I just never knew about it. ;) I should have asked sooner that’s for sure.

Thanks!

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A better way?

Sven Barth-2

Am 14.04.2016 10:45 schrieb "Ryan Joseph" <[hidden email]>:
>
>
> > On Apr 14, 2016, at 3:02 PM, Tony Whyman <[hidden email]> wrote:
> >
> > Reading through your post, I hope that you are aware that most circular dependencies can be avoided by referencing other units from the "uses" clause in the "implementation" section and keeping the "uses" clauses in "interfaces" down to those references strictly necessary for the unit's interface.
>
> I had no idea you could declare uses in the implementation! That could probably fix 90% of the problems I’m having which I’ve used abstract classes, dynamic method invocation and more recently interfaces to workaround. Don’t tell me this has been around for 20 years now I just never knew about it. ;) I should have asked sooner that’s for sure.

When was Delphi 3 released? Before '96? In that case it would indeed be more than 20 years ;)

Regards,
Sven


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A better way?

Ryan Joseph
In reply to this post by Graeme Geldenhuys-6

> On Apr 14, 2016, at 2:56 PM, Graeme Geldenhuys <[hidden email]> wrote:
>
> If you can give an actual example we can help. I've used TP then Delphi
> and now Free Pascal for more than 20+ years. I can probably count on one
> hand how many circular reference issues I had. So I dont' think it is
> such a big problem as you make out.
>
> Often moving uses clause references from the Interface section to the
> Implementation section solve the problem. Sometimes using a base class
> in the interface works. Sometimes using Interfaces (the language
> feature) is a much better approach.
>
> So again, if you can give an actual example of the various units, and
> how they relate (use each other), then we might be able to help you further.
>
> Regards,
>  Graeme


I’ve just browsed over some code and found moving uses to the implementation did in fact help. That’s really helpful thank you both. However I’m still seeing some common patterns which just don’t seem Pascal friendly. I started using these more often after using Objective-C on Mac frequently and I really like it but it requires me to hack around the compiler in Pascal.

In that example below the “main” class has children it talks to using an interface and returning a reference to itself for introspection. They are interdependent but Pascal doesn’t offer a way to expose a global namespace for both the units as far as I know.  In other languages I would make another “globals” unit and keep forward references to TClassA, TClassB and IClassA.

==============================

ClassB.pas:

uses
  ClassA;  // <----- circular reference but I need to know about ClassA

type
  TClassB = class (IClassA)
    // when we implement this method we may need to know some things
    // about the parent (TClassA) so it must be included
    procedure ClassDidThis (parent: TClassA; action: integer);
  end;

ClassA.pas:

uses
  ClassB;

type
  TClassA = class
    child: TClassB;
  end;

  // TClassA uses this interface to talk with it's “children” (TClassB)
  // and always returns a reference to itself because the children
  // often need to know about the parent also
  IClassA = interface
    procedure ClassDidThis (parent: TClassA; action: integer);
  end;

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A better way?

Ryan Joseph
In reply to this post by Sven Barth-2

> On Apr 14, 2016, at 4:14 PM, Sven Barth <[hidden email]> wrote:
>
> When was Delphi 3 released? Before '96? In that case it would indeed be more than 20 years ;)

I was using CodeWarrior back then (coming from a Mac background) and I didn’t switch to FPC until 2004 maybe. It would have been smart to learn about Delphi and new features but I just went ahead as normal missing lots of things that would help me in future years, like today for example. :)

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A better way?

Michael Van Canneyt
In reply to this post by Ryan Joseph


On Thu, 14 Apr 2016, Ryan Joseph wrote:

>
>> On Apr 14, 2016, at 2:56 PM, Graeme Geldenhuys <[hidden email]> wrote:
>>
>> If you can give an actual example we can help. I've used TP then Delphi
>> and now Free Pascal for more than 20+ years. I can probably count on one
>> hand how many circular reference issues I had. So I dont' think it is
>> such a big problem as you make out.
>>
>> Often moving uses clause references from the Interface section to the
>> Implementation section solve the problem. Sometimes using a base class
>> in the interface works. Sometimes using Interfaces (the language
>> feature) is a much better approach.
>>
>> So again, if you can give an actual example of the various units, and
>> how they relate (use each other), then we might be able to help you further.
>>
>> Regards,
>>  Graeme
>
>
> I’ve just browsed over some code and found moving uses to the implementation did in fact help. That’s really helpful thank you both. However I’m still seeing some common patterns which just don’t seem Pascal friendly. I started using these more often after using Objective-C on Mac frequently and I really like it but it requires me to hack around the compiler in Pascal.
>
> In that example below the “main” class has children it talks to using an interface and returning a reference to itself for introspection. They are interdependent but Pascal doesn’t offer a way to expose a global namespace for both the units as far as I know.  In other languages I would make another “globals” unit and keep forward references to TClassA, TClassB and IClassA.
>
> ==============================
>
> ClassB.pas:
>
> uses
>  ClassA;  // <----- circular reference but I need to know about ClassA
>
> type
>  TClassB = class (IClassA)
>    // when we implement this method we may need to know some things
>    // about the parent (TClassA) so it must be included
>    procedure ClassDidThis (parent: TClassA; action: integer);
>  end;
>
> ClassA.pas:
>
> uses
>  ClassB;
>
> type
>  TClassA = class
>    child: TClassB;
>  end;
You should not need TClassB here. You defeat the point of using an
interface.

   Child : IClassA;

should be sufficient.

Michael.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A better way?

Ryan Joseph

> On Apr 14, 2016, at 5:00 PM, Michael Van Canneyt <[hidden email]> wrote:
>
> You should not need TClassB here. You defeat the point of using an
> interface.

I’m using the interface for specific communication I want denoted in the interface but I’m still typically using properties of the child class in addition to the interface. Offloading all properties to the interface would work but it would be making accessing them very cumbersome because it requires using Support instead of just accessing them directly.

The interface was probably over complicating the example actually because the true problem is having this pattern of a parent->child relationship where both classes need to know about each other to some extent but putting them in the same unit causes clutter and pollution in other units namespaces. In this example it’s likely that many other units  use TClassB and it’s not exclusive to TClassA so putting them in the same unit doesn’t make sense.

Maybe I’m doing something stupid but other languages have forward declarations so I wonder why Pascal isn’t doing this also since it seems like the obvious solution.

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A better way?

Tony Whyman
Ryan,

> Maybe I’m doing something stupid but other languages have forward declarations so I wonder why Pascal isn’t doing this also since it seems like the obvious solution.
Pascal does have forward declarations e.g.

class TClassB;

class TClassA
private
   FClassBObject: TClassB;
end;

class TClassB
...
end;

Otherwise, if you really want to avoid defining interdependent classes
in the same unit (not sure why you want to avoid this) then try this:

unit unitA;

interface

type

class TClassA
private
   FClassBObject: TObject;
public
   procedure SomeProc;
end;

implementation

uses unitB;

Maybe I’m doing something stupid but other languages have forward declarations so I wonder why Pascal isn’t doing this also since it seems like the obvious solution.


procedure TClassA.SomeProc;
begin
   TClassB(FClassBObject).OtherProc;
end;

end.

unitB is pretty similar.

As long as you make sure that FClassBObject really is a TClassB object
when it is assigned, the above should all work. The only extra effort is
with the TClassB(...) wrapper for each reference to FClassBObject.

On 14/04/16 11:35, Ryan Joseph wrote:

>> On Apr 14, 2016, at 5:00 PM, Michael Van Canneyt <[hidden email]> wrote:
>>
>> You should not need TClassB here. You defeat the point of using an
>> interface.
> I’m using the interface for specific communication I want denoted in the interface but I’m still typically using properties of the child class in addition to the interface. Offloading all properties to the interface would work but it would be making accessing them very cumbersome because it requires using Support instead of just accessing them directly.
>
> The interface was probably over complicating the example actually because the true problem is having this pattern of a parent->child relationship where both classes need to know about each other to some extent but putting them in the same unit causes clutter and pollution in other units namespaces. In this example it’s likely that many other units  use TClassB and it’s not exclusive to TClassA so putting them in the same unit doesn’t make sense.
>
> Maybe I’m doing something stupid but other languages have forward declarations so I wonder why Pascal isn’t doing this also since it seems like the obvious solution.
>
> Regards,
> Ryan Joseph
>
> _______________________________________________
> fpc-pascal maillist  -  [hidden email]
> http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
>

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A better way?

Michael Van Canneyt
In reply to this post by Ryan Joseph


On Thu, 14 Apr 2016, Ryan Joseph wrote:

>
>> On Apr 14, 2016, at 5:00 PM, Michael Van Canneyt <[hidden email]> wrote:
>>
>> You should not need TClassB here. You defeat the point of using an
>> interface.
>
> I’m using the interface for specific communication I want denoted in the
> interface but I’m still typically using properties of the child class in
> addition to the interface.  Offloading all properties to the interface
> would work but it would be making accessing them very cumbersome because
> it requires using Support instead of just accessing them directly.
So, put bluntly, you are unwilling to do things properly, and then complain that the
language does not allow you to do this easily enough ?

No, you need to do things properly.

>
> The interface was probably over complicating the example actually because
> the true problem is having this pattern of a parent->child relationship
> where both classes need to know about each other to some extent but
> putting them in the same unit causes clutter and pollution in other units
> namespaces.  In this example it’s likely that many other units use TClassB
> and it’s not exclusive to TClassA so putting them in the same unit doesn’t
> make sense.

It certainly does make sense, if they are so intertwined.

This is not Java where you must put all classes in a single separate file.

If classes are so intertwined that they need detailed knowledge of each
other's property, put them in 1 unit.

It is as simple as that.

>
> Maybe I’m doing something stupid but other languages have forward declarations so I wonder why Pascal isn’t doing this also since it seems like the obvious solution.

Pascal has forward declarations. But only inside 1 unit.

Michael.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A better way?

Ryan Joseph
In reply to this post by Tony Whyman

> On Apr 14, 2016, at 5:51 PM, Tony Whyman <[hidden email]> wrote:
>
> unit unitA;
>
> interface
>
> type
>
> class TClassA
> private
>  FClassBObject: TObject;
> public
>  procedure SomeProc;
> end;
>
> implementation
>
> uses unitB;
>
> Maybe I’m doing something stupid but other languages have forward declarations so I wonder why Pascal isn’t doing this also since it seems like the obvious solution.
>
>
> procedure TClassA.SomeProc;
> begin
>  TClassB(FClassBObject).OtherProc;
> end;
>
> end.
>
> unitB is pretty similar.
>
> As long as you make sure that FClassBObject really is a TClassB object when it is assigned, the above should all work. The only extra effort is with the TClassB(...) wrapper for each reference to FClassBObject.

I use forward declarations sometimes but of course they need to be in the same block so they don’t solve this problem.

Yeah type casting. :) Like interfaces they work but they add a significant overhead and clutter (especially if they need to be used with dozens of methods in a unit) so that’s why I’m seeing if there’s a better way. However I think I like your idea of using them in conjunction with the uses in the implementation instead of my "abstract class" solution. Thanks for the tip.

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A better way?

Ryan Joseph
In reply to this post by Michael Van Canneyt

> On Apr 14, 2016, at 6:09 PM, Michael Van Canneyt <[hidden email]> wrote:
>
> So, put bluntly, you are unwilling to do things properly, and then complain that the
> language does not allow you to do this easily enough ?
>
> No, you need to do things properly.

I thought that was probably the answer I’d get but I wanted to ask anyways. I get there’s a Pascal way but it’s making the job more difficult then it should be so I opt for the quick and easy hack. Maybe it’s bad form but at the end of the day I just want to make things work and get the job done instead of getting held up on small details.

>
>>
>> The interface was probably over complicating the example actually because
>> the true problem is having this pattern of a parent->child relationship
>> where both classes need to know about each other to some extent but
>> putting them in the same unit causes clutter and pollution in other units
>> namespaces.  In this example it’s likely that many other units use TClassB
>> and it’s not exclusive to TClassA so putting them in the same unit doesn’t
>> make sense.
>
> It certainly does make sense, if they are so intertwined.
>
> This is not Java where you must put all classes in a single separate file.
>
> If classes are so intertwined that they need detailed knowledge of each
> other's property, put them in 1 unit.
>
> It is as simple as that.

That would be a solution but it’s not very pretty. Having 2 classes in the same unit that need knowledge of each other but are still mutually exclusive is also bad design in my opinion.

Why is it so terrible that classes could have forward declarations outside of a single block anyways? It seems like a practical and efficient solution that requires lots of extra work in design or typecasting/interfaces.

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A better way?

Michael Van Canneyt


On Thu, 14 Apr 2016, Ryan Joseph wrote:

>
>> On Apr 14, 2016, at 6:09 PM, Michael Van Canneyt <[hidden email]> wrote:
>>
>> So, put bluntly, you are unwilling to do things properly, and then complain that the
>> language does not allow you to do this easily enough ?
>>
>> No, you need to do things properly.
>
> I thought that was probably the answer I’d get but I wanted to ask anyways. I get there’s a Pascal way but it’s making the job more difficult then it should be so I opt for the quick and easy hack. Maybe it’s bad form but at the end of the day I just want to make things work and get the job done instead of getting held up on small details.
>
>>
>>>
>>> The interface was probably over complicating the example actually because
>>> the true problem is having this pattern of a parent->child relationship
>>> where both classes need to know about each other to some extent but
>>> putting them in the same unit causes clutter and pollution in other units
>>> namespaces.  In this example it’s likely that many other units use TClassB
>>> and it’s not exclusive to TClassA so putting them in the same unit doesn’t
>>> make sense.
>>
>> It certainly does make sense, if they are so intertwined.
>>
>> This is not Java where you must put all classes in a single separate file.
>>
>> If classes are so intertwined that they need detailed knowledge of each
>> other's property, put them in 1 unit.
>>
>> It is as simple as that.
>
> That would be a solution but it’s not very pretty. Having 2 classes in the
> same unit that need knowledge of each other but are still mutually
> exclusive is also bad design in my opinion.
Each is entitled to his opinion.

Practical people use the tools at their disposal how they are meant to use.

In this case the tool tells you that the 2 classes should be in 1 unit.
So, you can waste your time looking for a way out, or just use the tool as
it is meant.

Michael.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A better way?

Ryan Joseph

> On Apr 14, 2016, at 9:25 PM, Michael Van Canneyt <[hidden email]> wrote:
>
> In this case the tool tells you that the 2 classes should be in 1 unit.
> So, you can waste your time looking for a way out, or just use the tool as
> it is meant.

I think I prefer using type casting or abstract classes more than mixing 2 mutually exclusive classes into one unit even though they may have dependancies on each other. Editing and navigating the files would be confusing for one since there’s no obvious name to use for the file now.

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A better way?

Florian Klämpfl
In reply to this post by Michael Van Canneyt
Am 14.04.2016 um 16:25 schrieb Michael Van Canneyt:

>>
>> That would be a solution but it’s not very pretty. Having 2 classes in the
>> same unit that need knowledge of each other but are still mutually
>> exclusive is also bad design in my opinion.
>
> Each is entitled to his opinion.
>
> Practical people use the tools at their disposal how they are meant to use.
>
> In this case the tool tells you that the 2 classes should be in 1 unit.
> So, you can waste your time looking for a way out, or just use the tool as
> it is meant.
>

Or do it in two separate include files and add include both in the unit. FPC can do the C++ way :))))

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A better way?

Ewald-2
In reply to this post by Ryan Joseph
On 14/04/16 16:46, Ryan Joseph wrote:
> I think I prefer using type casting or abstract classes more than mixing 2 mutually exclusive classes into one unit even though they may have dependancies on each other. Editing and navigating the files would be confusing for one since there’s no obvious name to use for the file now.

Mutually exclusive classes are mutually exclusive to classes which have
dependencies on one another ;-)

Or am I missing something?

--
Ewald
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A better way?

Ryan Joseph

> On Apr 15, 2016, at 1:23 AM, Ewald <[hidden email]> wrote:
>
> Mutually exclusive classes are mutually exclusive to classes which have
> dependencies on one another ;-)
>
> Or am I missing something?

In the example I gave TClassB may be used by many other units but TClassA is only used with one other unit. TClassB is communicating with TClassA via interfaces but it’s still useful standalone and distinct in nature.

This happens to me all the time actually where I need to expose some type information or an interface to both classes because I don’t want them merged.

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A better way?

Ryan Joseph
In reply to this post by Florian Klämpfl
I’ve cleaned up some code by declaring uses in the implementation and using generic untyped variables like TObject for parameters. This compiles but I’m left with lots of ugly type casting in the implementation because the parameters for methods are untyped. Yes it works but I feel like the compiler could be helping more.

Just as an idea to float out here’s a suggestion for a “hint” syntax which would be used to solve the type casting issue by doing some dynamic typing.

Sure you could put those all in file for this example but in the real world there may be dozens of TClassB subclasses which would make the unit 10,000’s of lines long and impossible to navigate. The other solution as mentioned would be to use $includes and still use the single unit approach (how reliable is this? I’ve never tried).

Does this look like more work than using $includes? Maybe I need to seriously considering reorganizing my projects to work like this but it just feels wrong for some reason.

=====================

unit Globals;
interface

type
        HClassB = 'TClassB'; // declare a hint to the class name

implementation
end.

=====================

unit ClassB;
interface
uses
        ClassA;
       
type
        TClassB = class
                procedure DoSomething (sender: TClassA);
        end;

implementation

procedure TClassB.DoSomething (sender: TClassA);
begin
        // full access to TClassA
end;

end.

=====================

unit ClassA;
interface
uses
        Globals;
       
type
        TClassA = class
                // The interface section can't know about TClassB so we declare a
                // class name hint from Globals.pas (HClassB) and assign the paramter with it
                // using the "hint" syntax
                procedure SetValue (value: TObject[HClassB]);
        end;

implementation

// use ClassB now so hints evaluate
uses
        ClassB;

procedure TClassA.SetValue (value: TObject[HClassB]);
begin
        // behind the scenes the compiler (or preparser if FPC has one) replaces the text "TObject[HClassB]" to “TClassB" or throws an error if the identifier TClassB is not found
        value.DoSomething(self);
end;

end.

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: A better way?

Graeme Geldenhuys-6
On 2016-04-15 07:15, Ryan Joseph wrote:
> Sure you could put those all in file for this example but in the real
> world there may be dozens of TClassB subclasses which would make the
> unit 10,000’s of lines long and impossible to navigate.

Big units have never been a problem to navigate for me. Years ago I've
implemented the "procedure list" IDE add-on for Lazarus and Maximus. I
can find locations in code in one or two seconds (however fast I can
type). Procedure List (Alt+G) is now installed as standard with Lazarus IDE.

Use bookmarks to jump between often used locations.

Lazarus IDE includes a feature called Code Explorer, but I find
Procedure List much faster.


> The other
> solution as mentioned would be to use $includes and still use the
> single unit approach (how reliable is this? I’ve never tried).

Yes, include files work very well (much better than in Delphi). Lazarus
IDE knows how to handle include files very well to. So too does MSEide,
but Lazarus has a few more tricks.

The Free Pascal code (compiler and RTL) uses include files extensively.

Regards,
  Graeme

--
fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/

My public PGP key:  http://tinyurl.com/graeme-pgp
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
12