Difference between revisions of "Extract internals"

From Liberty Eiffel Wiki
Jump to navigation Jump to search
 
m
 
(7 intermediate revisions by 4 users not shown)
Line 1: Line 1:
[[Category: Book]]
+
[[Category:Tool]]
The <tt>extract_internals</tt> program was written as an attempt to fix a common problem when using object persistence: if two programs are going to send objects to each other, how do they know what objects to expect to receive? The <tt>extract_internals</tt> program analyses a program and outputs the list of object types that this program can send. The list is written in a format that can easily be used by the program that receives the objects.
+
The <tt>extract_internals</tt> program was written in an attempt to fix a common problem when using object persistence: if two programs are going to send objects to each other, how do they know what objects to expect to receive? The <tt>extract_internals</tt> program analyses a program and outputs the list of object types that this program can send. The list is written in a format that can easily be used by the program that receives the objects.
   
 
==The problem==
 
==The problem==
Three problems, actually
+
Three problems, actually:
# When compiling a program, SmartEiffel only generates code to support classes of which instances are <tt>create</tt>d in that program. Receiving objects through the STORABLE interface does not count as creating for this matter, so we need to cheat SmartEiffel into believing that all those types that can be received through the STORABLE interface can also be created locally (that is, mark those types as <i>live</i>).
+
# When compiling a program, Liberty Eiffel only generates code to support classes of which instances are <tt>create</tt>d in that program. Receiving objects through the STORABLE interface does not count as creating for this matter, so we need to cheat Liberty Eiffel into believing that all those types that can be received through the STORABLE interface can also be created locally (that is, mark those types as <i>live</i>).
# We also need the compiler to know that we want to do introspection on types that we want to receive through the STORABLE interface, since STORABLE relies on introspection. Mainly, this means marking TYPED_INTERNALS[<i>the type that we want to receive</i>] as live.
+
# The compiler also needs to know that we want to do introspection on types that we want to receive through the STORABLE interface, since STORABLE relies on introspection. Mainly, this means marking TYPED_INTERNALS[<i>the type that we want to receive</i>] as live.
# Actually, SmartEiffel even strips unused attributes off classes (at least in -boost mode). If two different programs use the same class, there is no guarantee that the same attributes will be stripped for both programs. That is unfortunate if those progams exchange objects.
+
# Actually, Liberty Eiffel even strips unused attributes off classes (at least so in -boost mode). If two different programs use the same class, there is no guarantee that the same attributes will be stripped for both programs. That is unfortunate if those progams exchange objects.
   
 
==Installing the tool==
 
==Installing the tool==
The first version of the extracting tool is bundled with SmartEiffel 2.2 final, so start by downloading and installing that if you don't already have it.
+
The first version of the extracting tool was bundled with SmartEiffel 2.2 final, Liberty Eiffel's predecessor.
http://smarteiffel.loria.fr/general/download.html
 
   
 
Now, go to some directory in your path (for instance, <tt>SmartEiffel/bin</tt>) and compile the extractor tool:
 
Now, go to some directory in your path (for instance, <tt>SmartEiffel/bin</tt>) and compile the extractor tool:
  +
 
se c -boost -no_gc -no_split -clean -o extract_internals extract_internals
 
se c -boost -no_gc -no_split -clean -o extract_internals extract_internals
  +
 
You may also want to add <tt>extract_internals</tt> to the [[Configuration file#Tools|<tt>[tools]</tt> section of your SmartEiffel configuration file]] to be able to use extract_internals through the se front-end. The configuration file is [[Configuration file#Where_is_this_file|often named <tt>.serc</tt>, <tt>se.cfg</tt> or <tt>system.se</tt>]].
 
You may also want to add <tt>extract_internals</tt> to the [[Configuration file#Tools|<tt>[tools]</tt> section of your SmartEiffel configuration file]] to be able to use extract_internals through the se front-end. The configuration file is [[Configuration file#Where_is_this_file|often named <tt>.serc</tt>, <tt>se.cfg</tt> or <tt>system.se</tt>]].
   
Line 87: Line 88:
   
 
This will generate two files:
 
This will generate two files:
* <tt>writer_internals_helper.e</tt> is the list of live classes that WRITER can export. This list is written as an Eiffel class.
+
* <tt>writer_internals_helper.e</tt> does not need to be used anymore,
* <tt>writer_internals_helper.se</tt> is the list of live attributes of those classes. This list is written as a [[Cecil]] file.
+
* <tt>writer_internals_helper.se</tt> is the list of live classes that WRITER can export and the list of live attributes of those classes. This list is written as a [[Cecil]] file.
   
To use the information we obtained, we have to add a call to WRITER_INTERNALS_HELPER.storable_quit as the last instruction of READER. Then we compile READER using the cecil file writer_internals_helper.se. Here is the modified READER:
+
To use the information we obtained, we have to compile READER using the cecil file writer_internals_helper.se.
 
class READER
 
 
creation
 
make
 
 
feature
 
make is
 
local
 
r: XML_REPOSITORY[DATA]
 
x: DATA
 
do
 
create r.from_file ("data.xml")
 
x := r.at ("qoocku")
 
check
 
x /= Void
 
end
 
print (x.a)
 
<span style="color: #ff0000">(create {WRITER_INTERNALS_HELPER}).storable_quit</span>
 
end
 
 
end
 
   
 
Now we can compile the WRITER and the READER. Remember to use the cecil file when compiling the READER.
 
Now we can compile the WRITER and the READER. Remember to use the cecil file when compiling the READER.
   
 
se c -o writer writer
 
se c -o writer writer
se c -o reader reader -cecil writer_internals_helper.se
+
se c -o reader reader <span style="color: #ff0000">-cecil writer_internals_helper.se</span>
   
 
Now we can enjoy the result of our work and run the writer, followed by the reader...
 
Now we can enjoy the result of our work and run the writer, followed by the reader...
Line 146: Line 125:
 
end
 
end
   
Now, we run <tt>extract_internals</tt> on common_root.e, and we add the following line at the end of <tt>PROGRAM_1.make</tt>, <tt>PROGRAM_2.make</tt> and <tt>PROGRAM_3.make</tt>:
+
Now, we run <tt>extract_internals</tt> on common_root.e.
 
(create {COMMON_ROOT_INTERNALS_HELPER}).storable_quit
 
   
 
We can then compile <tt>PROGRAM_1</tt>, <tt>PROGRAM_2</tt> and <tt>PROGRAM_3</tt> as usual, just adding the <tt>-cecil common_root_internals_helper.se</tt> parameter.
 
We can then compile <tt>PROGRAM_1</tt>, <tt>PROGRAM_2</tt> and <tt>PROGRAM_3</tt> as usual, just adding the <tt>-cecil common_root_internals_helper.se</tt> parameter.
  +
  +
=== Options ===
  +
  +
==== Information ====
  +
  +
{| cellspacing="4" cellpadding="0" width="100%"
  +
|-
  +
| width="20%" valign="top" | <code>-help</code>
  +
| Display a short summary of the command line syntax, with a complete list of the compiler options.
  +
|-
  +
| valign="top" | <code>-verbose</code>
  +
| Display (an enormous amount of) information during compilation: a complete trace of files loaded, [[type inference]] scores, generated files and so on.
  +
|-
  +
| valign="top" | <code>-version</code>
  +
| Display the SmartEiffel version number.
  +
|}
  +
  +
==== Warnings ====
  +
  +
{| cellspacing="4" cellpadding="0" width="100%"
  +
|-
  +
| width="20%" valign="top" | <code>-style_warning</code>
  +
| Display warning messages about non-compliance with Eiffel style rules.
  +
|-
  +
| valign="top" | <code>-no_warning</code>
  +
| Suppress all warning messages.
  +
|}
  +
  +
==== Message Styles ====
  +
  +
{| cellspacing="4" cellpadding="0" width="100%"
  +
|-
  +
| width="20%" valign="top" | <code>-flymake_mode</code>
  +
| Display messages in a compact format suitable for processing by tools such as Emacs' Flymake mode.
  +
|}
   
 
==FAQ==
 
==FAQ==

Latest revision as of 19:01, 14 June 2016

The extract_internals program was written in an attempt to fix a common problem when using object persistence: if two programs are going to send objects to each other, how do they know what objects to expect to receive? The extract_internals program analyses a program and outputs the list of object types that this program can send. The list is written in a format that can easily be used by the program that receives the objects.

The problem

Three problems, actually:

  1. When compiling a program, Liberty Eiffel only generates code to support classes of which instances are created in that program. Receiving objects through the STORABLE interface does not count as creating for this matter, so we need to cheat Liberty Eiffel into believing that all those types that can be received through the STORABLE interface can also be created locally (that is, mark those types as live).
  2. The compiler also needs to know that we want to do introspection on types that we want to receive through the STORABLE interface, since STORABLE relies on introspection. Mainly, this means marking TYPED_INTERNALS[the type that we want to receive] as live.
  3. Actually, Liberty Eiffel even strips unused attributes off classes (at least so in -boost mode). If two different programs use the same class, there is no guarantee that the same attributes will be stripped for both programs. That is unfortunate if those progams exchange objects.

Installing the tool

The first version of the extracting tool was bundled with SmartEiffel 2.2 final, Liberty Eiffel's predecessor.

Now, go to some directory in your path (for instance, SmartEiffel/bin) and compile the extractor tool:

se c -boost -no_gc -no_split -clean -o extract_internals extract_internals

You may also want to add extract_internals to the [tools] section of your SmartEiffel configuration file to be able to use extract_internals through the se front-end. The configuration file is often named .serc, se.cfg or system.se.

Update: 2.3's installer automatically installs this tool.

One-way sending

Let's see how to use the extract_internals tool. We have two programs, WRITER and READER. We want the WRITER to send DATA objects to the READER through an xml file called data.xml. Here's the source code of the WRITER (programs courtesy of Damian Dobroczyński):

class WRITER

creation
   make

feature
   make is
      local
         r: XML_REPOSITORY[DATA]
         x: DATA
      do
         create r.make
         create x.make
         r.put (x, "qoocku")
         r.commit_to_file ("data.xml")
      end

end

And now for the READER. Unfortunately, this code does not work because the compiler does not know yet that objects of type DATA can be created by READER (through the repository).

class READER

creation
   make

feature
   make is
      local
         r: XML_REPOSITORY[DATA]
         x: DATA
      do
         create r.from_file ("data.xml")
         x := r.at ("qoocku")
         check
            x /= Void
         end
         print (x.a)
      end

end

For the sake of completeness, here is the code of DATA (it is not important for this discussion)

class DATA

inherit
   STORABLE

creation
   make

feature
   a: STRING

   make is
      do
         a := "Qoocku"
      end

end

Now the fun stuff begins: we use extract_internals to get the list of objects that can be created by the WRITER:

extract_internals writer

This will generate two files:

  • writer_internals_helper.e does not need to be used anymore,
  • writer_internals_helper.se is the list of live classes that WRITER can export and the list of live attributes of those classes. This list is written as a Cecil file.

To use the information we obtained, we have to compile READER using the cecil file writer_internals_helper.se.

Now we can compile the WRITER and the READER. Remember to use the cecil file when compiling the READER.

se c -o writer writer
se c -o reader reader -cecil writer_internals_helper.se

Now we can enjoy the result of our work and run the writer, followed by the reader...

./writer
./reader

...and enjoy the output, namely "Qoocku" (By the way does that mean anything?)

N-way sharing

If you have several programs sharing data through the STORABLE interface, you could arguably call extract_internals for each of them, and add calls to all the xxx_INTERNALS_HELPER.storable_quit at the end of all of then. Quite possibly, you would have to run extract_internals several times until the helpers stabilise. But there's an easier way.

Let's assume we have three communicating programs, and their root classes/root procedures are PROGRAM_1.make, PROGRAM_2.make and PROGRAM_3.make. Now, we create a virtual common root:

class COMMON_ROOT

creation
   make

feature
   make is
      do
         create PROGRAM_1.make
         create PROGRAM_2.make
         create PROGRAM_3.make
      end

end

Now, we run extract_internals on common_root.e.

We can then compile PROGRAM_1, PROGRAM_2 and PROGRAM_3 as usual, just adding the -cecil common_root_internals_helper.se parameter.

Options

Information

-help Display a short summary of the command line syntax, with a complete list of the compiler options.
-verbose Display (an enormous amount of) information during compilation: a complete trace of files loaded, type inference scores, generated files and so on.
-version Display the SmartEiffel version number.

Warnings

-style_warning Display warning messages about non-compliance with Eiffel style rules.
-no_warning Suppress all warning messages.

Message Styles

-flymake_mode Display messages in a compact format suitable for processing by tools such as Emacs' Flymake mode.

FAQ

You suggest to only initialise introspection at the end of the program. Isn't that a little late?

No, because the important action of storable_quit is performed at compile-time, not at run-time.

Some of the creation procedures used by xxx_INTROSPECTION_HELPER have nasty side-effects

That's no problem, because those creation instructions never actually get executed (see the "die" instruction above). We only want the compiler to believe that those instructions could could possibly get executed one day.

Some of the creation instructions in xxx_INTROSPECTION_HELPER will crash at run time because they have invalid parameters

No, because those instructions won't get executed.