|
Boost : |
Subject: [boost] C# LINQ-like library: Boost.Qlang.
From: Germán Diago (germandiago_at_[hidden])
Date: 2009-10-16 07:22:24
IMPORTANT: Sorry I forgot to attach the code. This is the correct
mail, ignore the other one.
Hello. I'm working on a library that is very early in its development,
but I wanted to share
it to get some feedback and to know if someone would be interested in it.
I have named the library Boost.Qlang, and, over the time, maybe I
could launch it.
Now about the library. Boost.Qlang is a library inspired in C#'s linq
extensions.
For now, as this is an early prototype, Boost.Qlang is implemented
ONLY for c++0x making
use of lambdas and variadic templates. The plan is to make it compatible with
c++98 , but as I'm not very familiar with Boost.Preprocessor library,
I sticked to c++0x to test
the ideas.
Now for the library, by example. The library uses this struct (for
testing) and this vector:
struct Person {
std::string name_;
std::string surname_;
int age_;
public:
Person(const std::string & name, const std::string & surname,
int age) :
name_(name), surname_(surname), age_(age) {}
};
vector<Person> persons = { {"German", "Gallardone", 23}, {"Pedro", "Ruiz", 28},
{"Hilario", "Pinose", 34},
{"Manolito", "Gafotas", 29},
{"Tomas", "Todonte", 56}, {"Tomas",
"Ruiz", 33}};
Example 1:
auto query = from(persons).where([](const Person & d) { return
d.surname_ == "Ruiz"; }).
select(full_object);
What does this do? It selects Persons with surname "Ruiz". The
full_object in select is a placeholder
that selects the full object. The query is NOT executed, instead, a
select_<...> object is returned, which
represents a query.
A query models the Range concept, so if you want to evaluate the
query, you can do it like this:
for (auto it = query.begin(); it != query.end(); ++it)
cout << person.surname_ << std::endl;
Any struct can be used for queries without any kind of adaptation.
The original range cannot be modified through the query. Everything
returned is a new object.
If you want to evaluate immediatly the query and store it, to_list()
and to_vector() can be used from the
query object:
vector<Person> vec = query.to_vector();
Example 2. Selecting a subset of the fields in Person.
Sometimes we want to select just a subset of the fields in a query.
This is done like this:
auto query2 = from(persons).where([](const Person & d) { return
d.surname_ == "Ruiz"; }).
select(&Person::surname_);
The query returns elements of type boost::tuple<std::string>
containing the surname. Maybe in the future
a specialized tuple will be returned, in order to access the elements
in a readable way, maybe something like:
get<&Doctor::surname>(elem);
For now just a field can be selected at the same time in select, but
the plan is to be able to select as many as necessary.
There are also plans to be able to use as placeholders in select unary
member functions (for now it's just pointer to member data) and
lambdas. For example something like this could be done:
auto myquery = from(persons).where([](const Person & d) { return
d.surname == "Ruiz";}).
select([](const Person & p) { return
std::string(p.name_ + " " + p.surname_; });
The return type would be that of the lambda.
Example 3. Nested queries:
auto query3 = from(query).where([](const Person & a) { return a.age_ == 28; }).
select(&Person::name_);
This query holds an object with a subquery inside it. You can traverse
the query and will get the expected results.
For now the library, in theory, can use any class that models the
range concept in the from clause.
The plan would be to add xml access (I don't know much about xml,
though) and for databases and so on, to get a
uniform interface for data access for every single data source you can imagine.
The library has been tested with gcc svn, which includes lambdas.
There is a file attached to this mail with a qlangtest.cpp
file in the qlang folder. The boost folder contains all the implementation.
Feedback is very welcome.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk