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