View Issue Details

IDProjectCategoryView StatusLast Update
0000061LDMud 3.5LPC Compiler/Preprocessorpublic2011-02-14 17:46
ReporterlarsAssigned To 
PrioritynormalSeverityfeatureReproducibilityN/A
Status newResolutionopen 
Summary0000061: 'use' directive to replace most uses of prototypes.
DescriptionSometimes it is desirable to let a module "/std/module/room" use functions from a different module "/std/module/props" with directly inheriting it. The traditional solution is to use prototypes, which can make debugging more difficult.

A directive

  use "/std/module/props";

could import all function declarations from "/std/module/props" as if defined by prototypes. Possible extended uses:

- The imported declarations would be flagged with their origination, so that any collision by another 'use' or explicite prototype could be detected.
- The name of "/std/module/props" could be stored in the program, so if at runtime an unresolved crossreference is detected, the compiler could give hints as to what could be missing. This can't be done at load time as in this case "/std/module/room" is necessarily incomplete, yet is loaded during the inheritance handling.

Other names for 'use' could be used, as long as they are different enough to 'inherit'. This excludes 'import', but 'require' could work (it has slightly different implied semantics, though).
Additional InformationBardioc suggested a version of

extern <prototype> by "<module>";

which could be added for ad-hoc uses. The attached file implements the grammar for these.
TagsNo tags attached.

Relationships

related to 0000233 resolvedGnomi LDMud 3.5 Programs, Blueprints, Virtual Inheritance 
related to 0000153 new LDMud 3.5 Improving the inherit list 
related to 0000152 resolvedGnomi LDMud 3.6 replace_program() and virtual variables 

Activities

2004-05-18 21:31

 

bardioc.diff (1,466 bytes)   
--- lex.c	2004-05-07 03:34:25.000000000 +0000
+++ /ETMSUsers4/lduening/tmp/lex.c	2004-05-18 14:12:37.000000000 +0000
@@ -494,6 +494,8 @@
    , { "virtual",        L_VIRTUAL       }
    , { "void",           L_VOID          }
    , { "while",          L_WHILE         }
+   , { "by",             L_BY            }
+   , { "extern",         L_EXTERN        }
    };
 
 /*-------------------------------------------------------------------------*/
--- prolang.y	2004-05-01 04:04:23.000000000 +0000
+++ /ETMSUsers4/lduening/tmp/prolang.y	2004-05-18 14:12:33.000000000 +0000
@@ -5152,6 +5152,8 @@
 %token L_VIRTUAL
 %token L_VOID
 %token L_WHILE
+%token L_BY
+%token L_EXTERN
 
 /* Textbook solution to the 'dangling else' shift/reduce conflict.
  */
@@ -5525,6 +5527,32 @@
 #endif /* USE_NEW_INLINES */
       }
 
+    | L_EXTERN type optional_star L_IDENTIFIER
+    
+      {
+          $2.typeflags |= $3;
+#ifdef USE_NEW_INLINES
+          def_function_typecheck($2, $4, MY_FALSE);
+#else /* USE_NEW_INLINES */
+          def_function_typecheck($2, $4);
+#endif /* USE_NEW_INLINES */
+      }
+
+      '(' argument ')'
+
+      {
+#ifdef USE_NEW_INLINES
+          def_function_prototype($7, MY_FALSE);
+#else /* USE_NEW_INLINES */
+          def_function_prototype($7);
+#endif /* USE_NEW_INLINES */
+      }
+
+      L_BY string_constant ';'
+
+      {
+      }
+      
     | type name_list ';' /* Variable definition */
       {
           if ($1.typeflags == 0)
bardioc.diff (1,466 bytes)   

zesstra

2009-01-08 07:25

administrator   ~0000865

Ok, I can imagine quite a number of applications for this as well. The one drawback I see: using #include and prototypes you can select specific prototypes to be declared, which might be good idea, if you need only a few out of hundreds. But as you don't have to use this feature...
I guess we have anyway some stuff to do in the compiler, so moving to 3.5. We can decide then if we want to implement it.

Gnomi

2009-01-08 08:30

manager   ~0000872

Doesn't this try to solve the same problem that virtual inherits were supposed to solve? Assuming that virtual inherits work why not virtual inherit "/std/module/props" instead of 'use' it?

zesstra

2009-01-08 09:17

administrator   ~0000874

Mhmm. Yes, you probably can solve these problems with virtual inherits.
With use or include you get a compilable, but mostly not executable object only for inheriting it (which is often completely fine).
With the virtual inherits it seems to be a much more complicated process for compiling and for resolving the functions and there are limitations like 'in case of replace_program() a program containing virtually inherited variables must be inherit first'.
And I might be wrong, but I have something in memory about merging or resolving the wrong variables and functions in complex trees. Some time ago we had 3-4 objects virtually inheriting and we had problems re-loading them and part of the ineritance tree without errors, so we fell back to the 'include the right prototypes' method (Im sorry, at that time I was not involved here, so I did not report that.) Or maybe it is a documentation issue which causes my disfavor.
I don't know if there is any difference in memory consumption or execution time between both methods.

Bardioc

2009-01-15 15:04

reporter   ~0000893

The memory problem (double variables) is exactly the problem that we wanted to address with this. If you mess up the virtual inheritance, you end up with an o-file that includes multiple values for the same variable.

Consider this example:

A <- B <- C
A <- D <- C

So both B and D inherit A.
If you do NOT virtually inherit A in B and D, you get twice the variables of A, thus a method call in B that modifies the variables of A will not be reflected by a query method in D that queries the variables of A.

Hope that I made my point clear here.

You are right, prototyps are completely fine, but if you change the fucntion definition you have to adapt all prototypes, thats why the extern definition came to my mind.

_xtian_

2009-01-16 13:22

reporter   ~0000905

I would support this.

Slightly offtopic: Is there a way to get "use" to include struct definitions into multiple files without directly inheriting the file defining the struct?
(as a sort of virtual inheritance for struct definitions).

Sharing struct definitions in a complex inheritance tree requires the definition to be inheritted multiple times.

Bardioc

2009-01-19 12:12

reporter   ~0000934

xtian as far as I know, and I talked about this with Lars structs are compile time structures that are program-based, thus if you define a structure foo in file a.c and in file b.c, they are NOT the same at run time, leading sometimes to weird errors like
   struct foo #33434 vs. struct foo #343434

To actually make "use" working for structures the need to be shared among programs, and the defining program would need to be reloaded in case it is gone. I'm not sure how much work this involves.

_xtian_

2009-01-20 06:52

reporter   ~0000935

Structs are shared by defining them in a common inherit in LPC. The same diagram as above applies, where A defines the struct:

A <- B <- C
A <- D <- C

B and D can exchange data typecast as their shared struct over function calls (type-safe btw).
But C needs to have the same inherit (A) twice.

Bardioc

2009-01-21 13:25

reporter   ~0000936

The problem is not the data typecast, but mainly the access to struct members ... the only thing a "use" for structs would be useful in your way is that a function prototyp will not lead to a compile error ... but in case a method uses the struct and accesses a member, the full definition is necessary to validate the member exists (and I would not want to pass on this).

I doubt that the only knowledge about the struct's name is useful, so I would vote for a maybe changed structure handling that introduces an own global namespace for structs rather than a program-based approach like it is now.

zesstra

2009-10-02 05:02

administrator   ~0001399

Gnomi suggest quite a time ago, that we should think of improving virtual inherits as an alternative. So I will relate some issues of virtual inherits with this issue to have an idea, what we should think of in this case.

zesstra

2011-02-14 17:46

administrator   ~0001986

As a comment: it still sounds easier to me to implement a 'use' which just imports all the public and protected/static functions as prototypes into the newly compiled program than 'fixing' the virtual inheritance. Not only in terms of code, but also conceptually.
That said, I would be happy to have both. One method results in a usable/cloneable object, the other just compiles, is smaller and can be used for inheritance...

Issue History

Date Modified Username Field Change
2004-05-18 21:31 lars New Issue
2004-05-18 21:31 lars File Added: bardioc.diff
2009-01-08 07:20 zesstra Project LDMud 3.3 => LDMud 3.5
2009-01-08 07:25 zesstra Note Added: 0000865
2009-01-08 08:30 Gnomi Note Added: 0000872
2009-01-08 09:17 zesstra Note Added: 0000874
2009-01-15 15:04 Bardioc Note Added: 0000893
2009-01-16 13:22 _xtian_ Note Added: 0000905
2009-01-19 12:12 Bardioc Note Added: 0000934
2009-01-20 06:52 _xtian_ Note Added: 0000935
2009-01-21 13:25 Bardioc Note Added: 0000936
2009-10-02 05:02 zesstra Note Added: 0001399
2009-10-02 05:02 zesstra Relationship added related to 0000233
2009-10-02 05:03 zesstra Relationship added related to 0000151
2009-10-02 05:03 zesstra Relationship added related to 0000153
2009-10-02 05:03 zesstra Relationship deleted related to 0000151
2009-10-02 05:04 zesstra Relationship added related to 0000152
2011-02-14 17:46 zesstra Note Added: 0001986