Is it possible to collect object usage information during compilation?

Jacob Carlborg via Digitalmars-d digitalmars-d at puremagic.com
Sat Jan 10 02:20:26 PST 2015


On 2015-01-10 07:46, DaveG wrote:
> Let me preface this by saying I only have a general conceptual
> understanding of compilers and know nothing about actual implementation.
>
> One common problem with Object-Relational Mapping (ORM) is what data to
> load and when. There is basically 2 options:
> 1. Load everything: This certainly works, but is very inefficient,
> particularly when you have a large number of fields or, even worse, have
> a derived field that causes a join on one or more tables. If you need
> all the data this is fine, but most of the time only a small subset is
> actually used. (lazy loading can mitigate some issues, but introduces
> other problems)
> 2. Specify what fields to populate: This can work, but makes more work
> for the user, adds complexity to user code, and often introduces bugs
> particularly over time as code changes. Implementation details are
> leaking into the interface.
>
> Basically, I'm looking for a way to "look ahead" to see what properties
> on an object are actually referenced (or not referenced) so we know what
> data needs to be loaded. Simple analysis for things like unused scope
> variables already exist, but this is needed for properties on each
> instance of a class (or struct). I guess this would require the compiler
> to make 2 passes once to trace each object and a second to do something
> with the data collected. This would potential cost a lot in compilation
> time so there would probably need to be some sort of annotation on the
> definition to indicate this type of check is necessary.
>
> I might be crazy, but it seems like the compiler has all the information
> necessary to figure this out and it would make user code simpler, less
> error prone, and more efficient. So does anybody have any idea on how to
> actually achieve this?

I'm not exactly sure if this is what you want but you can implement the 
"opDispatch" [1] method in a class or struct. This method will be called 
if no other method exists with the same name. There's also something 
called "alias this" [2] that allows you to do something similar.

class Foo
{
     void foo () {}
     void opDispatch (string name)() {}
}

auto f = new Foo;
f.foo(); // will call "foo"
f.bar(); // will be lowered to f.opDispatch!("bar")();

If you're implementing an ORM I would recommend executing queries 
lazily. You can do something like this:

class Person : ORM.Base
{
     String name;
     Int age;

// this method returns a range/proxy that implements the range api [3]
     static ORM.Range!(Person) all () {}
}

"String" would look something like this:

struct String
{
     alias get this;

     // this method will fetch the data from the database
     private string get ();
}

Using the interface would look something like this:

auto p = Person.all(); // no database query has been performed yet

// the range interface makes it possible to use a foreach
// when starting the foreach loop is when the first query will happen
foreach (e ; p)
{
     // this call will trigger a call to the "get" method in "String"
     // via the "alias this"
     string name = e.name;
     writeln(name);
}

[1] http://dlang.org/operatoroverloading.html#dispatch
[2] http://dlang.org/class.html#alias-this
[3] http://dlang.org/phobos/std_range.html#isInputRange

-- 
/Jacob Carlborg


More information about the Digitalmars-d mailing list