Giter VIP home page Giter VIP logo

Comments (5)

akheron avatar akheron commented on May 30, 2024

Hi and thanks.

Yes, I like the idea. I've actually been thinking about it myself, too, in the context of #37.

I'm only concerned about the declaration of k, v and __json_iterator__. If you do it like this, the declarations are not in the beginning of a block, which breaks strict C89 compatibility. You could also let the user declare them, but it makes using the macro a bit inconvenient, especially in the case of the iterator void pointer, as he doesn't even use it.

So, do you have any ideas on how to circumvent these problems?

from jansson.

coreh avatar coreh commented on May 30, 2024

Hmm, I see a few different ways of working around this.

A) First, you could keep the macro the way it is, and instruct C89 users to add an extra block around the foreach construct.

{json_object_foreach(key, value, object) 
{
    /* use key and value ... */
}}

But that's kind of ugly, and I'm not completely sure if C89 would accept a block like this. (But I think it should).

B) Another option is to only provide the json_object_foreach macro to translation units in C99 mode or newer, checking for the __STDC_VERSION__ macro.

#if __STDC_VERSION__ >= 199901L
    /* define json_object_foreach here */
#endif

That would sure limit the expressivity for people that need to remain using C89 on their code, but they're already quite limited (since they cannot declare variables inside for loops, for instance). Furthermore, they can still do things manually, so it wouldn't make using the library any harder for them. It would only not make it easier.

C) Yet another solution would be to provide another macro, say json_object_foreach_declare that would declare the variables needed for the loop (k, v and the "hidden" __json_iterator__), and remove the declarations from json_object_foreach. Their code would end up looking like:

void my_function(json_t *object)
{
    json_object_foreach_declare(key, value);

    /* code */

    json_object_foreach(key, value, object) {
        /* code */
    }
}

Which isn't the ideal in terms of brevity, but is much better than doing things manually.

To allow the C99 (and C11) folks to use json_object_foreach without json_object_foreach_declare, we can check for the version when defining the macro.

#if __STDC_VERSION__ >= 199901L
    /* define json_object_foreach with k, v, and __json_iterator__ declarations */
#else
    /* define json_object_foreach without any declarations */
#endif

And to allow the code containing json_object_foreach_declare to still be valid in C99, we can check for the version, too:

#if __STDC_VERSION__ >= 199901L
    /* define json_object_foreach_declare as ((void) 0) */
#else
    /* define json_object_foreach_declare normally */
#endif

I think this is the best solution, since it allows:

  1. C99 people to use foreach without having any previous declarations.
  2. C89 people to use foreach, after using a special declaration macro.
  3. C99 people to use the code written by the C89 people without any changes.

We still need to deal with multiple uses of json_object_foreach_declare on the same scope, but that can be done using the token pasting operator (##) from the C preprocessor.

I also think we need a better name than json_object_foreach_declare.

from jansson.

akheron avatar akheron commented on May 30, 2024

Option C sounds best to me, too. However, I don't see how ## could be used to deal with multiple uses json_object_foreach_declare. It also seems to me that there's no way to allow using nested json_object_foreach constructs for C89 folks.

from jansson.

coreh avatar coreh commented on May 30, 2024

Hmm... The code ends up looking a bit messy, but the idea is simple: We concatenate the k and v tokens with __json_iterator_, _ and __ to form a unique token.: __json_iterator_ ## k ## _ ## v ## __ => __json_iterator_k_v__.

Since k and v are going to change with each use of json_object_foreach_declare, the iterator token generated will also change. When we expand the json_object_foreach macro we can get the correct iterator, since we are given both k and v.

#define json_object_foreach_declare(k, v) const char *k; json_t *v; void * __json_iterator_ ## k ## _ ## v ## __

#define json_object_foreach(k, v, x) for (__json_iterator_ ## k ## _ ## v ## __ = json_object_iter(x); \
    __json_iterator_ ## k ## _ ## v ## __ && \
    (k = json_object_iter_key(__json_iterator_ ## k ## _ ## v ## __), v = json_object_iter_value(__json_iterator_ ## k ## _ ## v ## __), 1); \
    __json_iterator_ ## k ## _ ## v ## __ = json_object_iter_next(x, __json_iterator_ ## k ## _ ## v ## __))

This also allows for nested json_object_foreach, without problems:

json_object_foreach_declare(companyName, company);
json_object_foreach_declare(employeeName, employee);

json_object_foreach(companyName, company, town) {
    json_object_foreach(employeeName, employee, company) {
        /* do something with employee */
    }
}

Expanding to:

const char *companyName; json_t *company; void * __json_iterator_companyName_company__;
const char *employeeName; json_t *employee; void * __json_iterator_employeeName_employee__;

for (__json_iterator_companyName_company__ = json_object_iter(town); 
    __json_iterator_companyName_company__ &&
    (companyName = json_object_iter_key(__json_iterator_companyName_company__), company = json_object_iter_value(__json_iterator_companyName_company__), 1); \
    __json_iterator_companyName_company__ = json_object_iter_next(town, __json_iterator_companyName_company__)) {
    for (__json_iterator_employeeName_employee__ = json_object_iter(company); 
        __json_iterator_employeeName_employee__ &&
        (employeeName = json_object_iter_key(__json_iterator_employeeName_employee__), employee = json_object_iter_value(__json_iterator_employeeName_employee__), 1); \
        __json_iterator_employeeName_employee__ = json_object_iter_next(company, __json_iterator_employeeName_employee__)) {
        /* do something with employee */
    }
}

Which is quite unreadable because of the variable names, but should work just fine:

const char *a; json_t *b; void *c;
const char *d; json_t *e; void *f;

for (c = json_object_iter(x); c && (a = json_object_iter_key(c), b = json_object_iter_value(c), 1); c = json_object_iter_next(x, c)) {
    for (f = json_object_iter(b); f && (d = json_object_iter_key(f), e = json_object_iter_value(f), 1); f = json_object_iter_next(b, f)) {
        /* do something with e */
    }
}

from jansson.

akheron avatar akheron commented on May 30, 2024

Wow, that's clever. Feel free to submit a patch.

from jansson.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.