Does C++ have "with" keyword like Pascal?
Asked Answered
U

19

27

with keyword in Pascal can be use to quick access the field of a record. Anybody knows if C++ has anything similar to that?

Ex: I have a pointer with many fields and i don't want to type like this:

if (pointer->field1) && (pointer->field2) && ... (pointer->fieldn)

what I really want is something like this in C++:

with (pointer)
{
  if (field1) && (field2) && .......(fieldn)
}
Unlive answered 17/2, 2010 at 8:19 Comment(5)
Huh. Javascript has the with keyword and it does substantially the same thing; I didn't realize it had a pedigree reaching back to Pascal (!).Flattie
Maybe it comes from Cobol or ADA, who knows...Minnesinger
There is a with in Ada, but not with that meaning.Gumbo
There is a with in Vb and in Vb.Net with the same meaning too.Drastic
But in VB you need to say With obj / .X = x, so it's not as ambiguousPegmatite
H
10

In C++, you can put code in a method of the class being reference by pointer. There you can directly reference the members without using the pointer. Make it inline and you pretty much get what you want.

Hellenize answered 17/2, 2010 at 8:25 Comment(2)
What do you mean for “make it inline”? Can you declare the method just inside another function? It's weird...Irfan
@Irfan This answer is just suggesting to add a method to the class being used by with. Being inline allows it to go into a header but otherwise that's a red herring. Such a method must be declared in its original class, and defined outside any other function. My answer below has a workaround to both problems.Lissome
L
28

Probably the closest you can get is this: (this is just an academic exercise. Of course, you can't use any local variables in the body of these artificial with blocks!)

struct Bar {
    int field;
};

void foo( Bar &b ) {
    struct withbar : Bar { void operator()() {
        cerr << field << endl;
    }}; static_cast<withbar&>(b)();
}

Or, a bit more demonically,

#define WITH(T) do { struct WITH : T { void operator()() {
#define ENDWITH(X) }}; static_cast<WITH&>((X))(); } while(0)

struct Bar {
    int field;
};

void foo( Bar &b ) {
    if ( 1+1 == 2 )
        WITH( Bar )
            cerr << field << endl;
        ENDWITH( b );
}

or in C++0x

#define WITH(X) do { auto P = &X; \
 struct WITH : typename decay< decltype(X) >::type { void operator()() {
#define ENDWITH }}; static_cast<WITH&>((*P))(); } while(0)

        WITH( b )
            cerr << field << endl;
        ENDWITH;
Lissome answered 17/2, 2010 at 8:38 Comment(4)
Very nice :). I'd like to mention though that for those few of us that work with the Metrowerks compiler, this is quite likely not to work (it doesn't deal well with structs in a function)Kylakylah
@arke: really? That's surprising, I loved Metrowerks when it was the Mac standard. Hmm, it looks like they lost Howard Hinnant…Lissome
you can use static variables though.Highlands
In c++17, it would be better to do if(auto a=foo();true){/**/}Hartmann
R
22

no there is no such keyword.

Rewarding answered 17/2, 2010 at 8:21 Comment(0)
C
17

I like to use:

    #define BEGIN_WITH(x) { \
        auto &_ = x;

    #define END_WITH() }

Example:

    BEGIN_WITH(MyStructABC)
    _.a = 1;
    _.b = 2;
    _.c = 3;
    END_WITH()
Cravens answered 21/2, 2015 at 11:37 Comment(0)
H
10

In C++, you can put code in a method of the class being reference by pointer. There you can directly reference the members without using the pointer. Make it inline and you pretty much get what you want.

Hellenize answered 17/2, 2010 at 8:25 Comment(2)
What do you mean for “make it inline”? Can you declare the method just inside another function? It's weird...Irfan
@Irfan This answer is just suggesting to add a method to the class being used by with. Being inline allows it to go into a header but otherwise that's a red herring. Such a method must be declared in its original class, and defined outside any other function. My answer below has a workaround to both problems.Lissome
S
9

Even though I program mostly in Delphi which has a with keyword (since Delphi is a Pascal derivative), I don't use with. As others have said: it saves a bit on typing, but reading is made harder.

In a case like the code below it might be tempting to use with:

cxGrid.DBTableView.ViewData.Records.FieldByName('foo').Value = 1;
cxGrid.DBTableView.ViewData.Records.FieldByName('bar').Value = 2;
cxGrid.DBTableView.ViewData.Records.FieldByName('baz').Value = 3;

Using with this looks like this

with cxGrid.DBTableView.ViewData.Records do
begin
  FieldByName('foo').Value = 1;
  FieldByName('bar').Value = 2;
  FieldByName('baz').Value = 3;
end;

I prefer to use a different technique by introducing an extra variable pointing to the same thing with would be pointing to. Like this:

var lRecords: TDataSet;

lRecords := cxGrid.DBTableView.ViewData.Records;

lRecords.FieldByName('foo').Value = 1;
lRecords.FieldByName('bar').Value = 2;
lRecords.FieldByName('baz').Value = 3;

This way there is no ambiguity, you save a bit on typing and the intent of the code is clearer than using with

Scream answered 17/2, 2010 at 9:2 Comment(1)
This strategy works with C++ too, using a local T& or T const& variable to hold a reference to the long expression (which must be a proper lvalue in the T& case). To make it visually stand out, I usually name the variable _.Bern
A
6

No, C++ does not have any such keyword.

Adulteration answered 17/2, 2010 at 8:22 Comment(0)
R
6

The closest you can get is method chaining:

myObj->setX(x)
     ->setY(y)
     ->setZ(z)

for setting multiple fields and using for namespaces.

Rudich answered 17/2, 2010 at 12:34 Comment(2)
This is actually sick good, because encapsulation is preserved... Thanks for making the connection!Regulus
it is NOT BY FAR the same!Phobos
C
5

C++ does not have a feature like that. And many consider "WITH" in Pascal to be a problem because it can make the code ambiguous and hard to read, for example it hard to know if field1 is a member of pointer or a local variable or something else. Pascal also allows multiple with-variables such as "With Var1,Var2" which makes it even harder.

Coenurus answered 17/2, 2010 at 8:25 Comment(6)
There is always the question that if something can be abused, means that it is bad.Tripterous
Sure, because name lookup in C++ is so straightforward. No -1, but I think the "can make code ambiguous" argument falls flat when you consider the case of argument-dependent lookup for functions, especially for instantiations of function templates.Bern
I agree it can be useful but I've seen it abused so many times now that I stay away from using it. In particular it can bite you if field1 is renamed in the record so your with-code now suddenly silently refers to another variable in scope with the same name. Instead of with I use one of the other approaches suggested here: use a local variable with short name or move it to a function/method.Coenurus
Upvote. The worst language feature. Consider this abomination: with struct1, struct2.substruct3, struct4.substruct5.ptrstruct6^... Seen it.Drummer
Visual Basic tidied up the syntax by requiring the fields belonging to the 'with' to be prefixed with a "." - it also helped syntax completion etc. Our host Joel did that :)Kleper
Not dangerous if you apply it only on a single type (record, structure, object, etc). In other words, never mix objects inside the "with" and your safe.Phobos
M
3
with (OBJECT) {CODE}

There is no such thing in C++.
You can put CODE as is into a method of OBJECT, but it is not always desirable.

With C++11 you can get quite close by creating alias with short name for OBJECT.
For example code given in question it will look like so:

{
    auto &_ = *pointer;
    if (_.field1 && ... && _.fieldn) {...}
}

(The surrounding curly braces are used to limit visibility of alias _ )

If you use some field very often you can alias it directly:

auto &field = pointer->field;
// Even shorter alias:
auto &_ = pointer->busy_field;
Millur answered 27/12, 2014 at 20:59 Comment(0)
D
3

No, there is no with keyword in C/C++.

But you can add it with some preprocessor code:

/* Copyright (C) 2018 Piotr Henryk Dabrowski, Creative Commons CC-BY 3.0 */

#define __M2(zero, a1, a2, macro, ...) macro

#define __with2(object, as) \
    for (typeof(object) &as = (object), *__i = 0; __i < (void*)1; ++__i)

#define __with1(object) __with2(object, it)

#define with(...) \
    __M2(0, ##__VA_ARGS__, __with2(__VA_ARGS__), __with1(__VA_ARGS__))

Usage:

with (someVeryLongObjectNameOrGetterResultOrWhatever) {
    if (it)
        it->...
    ...
}

with (someVeryLongObjectNameOrGetterResultOrWhatever, myObject) {
    if (myObject)
        myObject->...
    ...
}

Simplified unoverloaded definitions (choose one):

unnamed (Kotlin style it):

#define with(object) \
    for (typeof(object) &it = (object), *__i = 0; __i < (void*)1; ++__i)

named:

#define with(object, as) \
    for (typeof(object) &as = (object), *__i = 0; __i < (void*)1; ++__i)

Of course the for loop always has only a single pass and will be optimized out by the compiler.

Doenitz answered 26/8, 2018 at 8:34 Comment(0)
S
1

The following approach relies on Boost. If your compiler supports C++0x's auto then you can use that and get rid of the Boost dependence.

Disclaimer: please don't do this in any code that must be maintained or read by someone else (or even by yourself in a few months):

#define WITH(src_var)                                             \
    if(int cnt_ = 1)                                              \
        for(BOOST_AUTO(const & _, src_var); cnt_; --cnt_)


int main()
{
    std::string str = "foo";

    // Multiple statement block
    WITH(str)
    {
        int i = _.length();
        std::cout << i << "\n";
    }

    // Single statement block
    WITH(str)
        std::cout << _ << "\n";

    // Nesting
    WITH(str)
    {
        std::string another("bar");
        WITH(another)
            assert(_ == "bar");
    }
}
Solemn answered 17/2, 2010 at 11:19 Comment(0)
H
1

First I've heard that anybody doesn't like 'with'. The rules are perfectly straightforward, no different from what happens inside a class in C++ or Java. And don't overlook that it can trigger a significant compiler optimization.

Highlight answered 17/2, 2010 at 11:28 Comment(0)
Z
1

Having written numerous parsers, this seems like a dead simple list look up for the named object, either static or dynamic. Further, I have never seen a situation where the compiler did not correctly identify the missing object and type, so all those lame excuses for not allowing a WITH ...ENDWITH construction would seem to be a lot of hooey. For the rest of us prone to long object names one workaround is to create simple defines. Couldn't resist, suppose I have:

    #include<something> 
    typedef int headache;
    class grits{
      public:
       void corn(void);
       void cattle(void);
       void hay(void);}; //insert function defs here
     void grits::grits(void)(printf("Welcome to Farm-o-mania 2012\n");};

    #define m mylittlepiggy_from_under_the_backporch.
    headache main(){
       grits mylittlepiggy_from_under_the_backporch;
         m corn();  //works in GCC
         m cattle();
         m hay();
      return headache;
Zaccaria answered 30/9, 2012 at 5:57 Comment(0)
M
1
#include <iostream>

using namespace std;

template <typename T>
struct with_iter {
  with_iter( T &val ) : p(&val) {}

  inline T* begin() { return p; }
  inline T* end() { return p+1; }

  T *p;
};

#define with( N, I ) for( auto &N : with_iter<decltype(I)>(I) )

int main() {

  with( out , cout ) {
    out << "Hello world!" << endl;
  }

  return 0;
}

Nuf said ...

Michaeu answered 6/3, 2019 at 13:49 Comment(0)
P
0

I can see one instance where 'with' is actually useful.

In methods for recursive data structures, you often have the case:

void A::method()
{
  for (A* node = this; node; node = node->next) {
    abc(node->value1);
    def(value2); // -- oops should have been node->value2
    xyz(node->value3);
  }
}

errors caused by typos like this are very hard to find.

With 'with' you could write

void A::method()
{
  for (A* node = this; node; node = node->next) with (node) {
    abc(value1);
    def(value2);
    xyz(value3);
  }
}

This probably doesn't outweight all the other negatives mentioned for 'with', but just as an interesting info...

Penrose answered 17/7, 2010 at 11:5 Comment(0)
A
0

Maybe you can:

auto p = *pointer;
if (p.field1) && (p.field2) && ... (p.fieldn)

Or create a small program that will understand with statements in C++ and translate them to some form of a valid C++.

Airtoair answered 20/10, 2011 at 19:5 Comment(1)
Probably should be auto &p = *pointer, since your code takes a copy.Chariot
I
0

I too came from the Pascal world..... .....and I also LOVE Python's use of with (basically having an automatic try/finally):

  with open(filename, "r") as file:
    for line in file:
      if line.startswith("something"):
        do_more()

That acts like a smart ptr object. It does not go into the block if the open failed; and when leaving the block, the file if closed.

Here is a sample very close to Pascal while also supporting Python's usage (assuming you have a smart object with destructor cleanup); You need newer C++ standard compilers for it to work.

    // Old way
    cxGrid_s cxGrid{};
    cxGrid.DBTableView.ViewData.Records.FieldByName.value["foo"] = 1;
    cxGrid.DBTableView.ViewData.Records.FieldByName.value["bar"] = 2;
    cxGrid.DBTableView.ViewData.Records.FieldByName.value["baz"] = 3;
    // New Way - FieldByName will now be directly accessible.
    // the `;true` is only needed if the call does not return bool or pointer type
    if (auto FieldByName = cxGrid.DBTableView.ViewData.Records.FieldByName; true)
    {
        FieldByName.fn1 = 0;
        FieldByName.fn2 = 3;
        FieldByName.value["foo"] = 1;
        FieldByName.value["bar"] = 2;
        FieldByName.value["baz"] = 3;
    }

And if you want even closer:

    #define with if

    with (auto FieldByName = cxGrid.DBTableView.ViewData.Records.FieldByName; true)
    // Similar to the Python example
    with (smartFile sf("c:\\file.txt"); sf)
    {
        fwrite("...", 1, 3, *sf);
    }
    // Usage with a smart pointer
    with (std::unique_ptr<class_name> p = std::make_unique<class_name>())
    {
        p->DoSomethingAmazing();

        // p will be released and cleaned up upon exiting the scope
    }

The (quick and dirty) supporting code for this example:

#include <map>
#include <string>
struct cxGrid_s {
    int g1, g2;
    struct DBTableView_s {
        int tv1, tv2;
        struct ViewData_s {
            int vd1, vd2;
            struct Records_s {
                int r1, r2;
                struct FieldByName_s{
                    int fn1, fn2;
                    std::map<std::string, int> value;
                } FieldByName;
            } Records;
        } ViewData;
    } DBTableView;
};

class smartFile
{
public:
    FILE* f{nullptr};
    smartFile() = delete;
    smartFile(std::string fn) { f = fopen(fn.c_str(), "w");    }
    ~smartFile()              { if (f) fclose(f); f = nullptr; }
    FILE* operator*()         { return f;            }
    FILE& operator->()        { return *f;           }
    operator bool() const     { return f != nullptr; }
};
Isis answered 5/3, 2021 at 16:53 Comment(0)
H
0

I was lamenting to PotatoSwatter (currently accepted answer) that I could not access variables declared in the enclosing scope with that solution. I tried to post this in a comment response to PotatoSwatter, but it's better as a whole post. It's all a bit over the top, but the syntax sugar is pretty nice!

#define WITH_SIG float x, float y, float z
#define WITH_ARG x, y, z

#define WITH(T,s) do { struct WITH : T { void operator()(s) {
#define ENDWITH(X,s) }}; static_cast<WITH&>((X))(s); } while(0)

class MyClass {
    Vector memberVector;
    static void myFunction(MyClass* self, WITH_SIG) {
        WITH(MyClass, WITH_SIG)
            memberVector = Vector(x,y,z);
        ENDWITH(*self, WITH_ARG);
    }
}
Hosier answered 5/6, 2021 at 0:48 Comment(0)
C
-3

A simple way to do this is as follows

class MyClass
{
    int& m_x;

    public MyClass(int& x)
    {
        m_x = x;
        m_x++;
    }

    ~MyClass()
    {
        m_x--;
    }
}
int main():
{
    x = 0;
    {
        MyClass(x)  // x == 1 whilst in this scope
    }
}

I've been writing python all day long and just scrapped this down before anyone takes me to the cleaners. In a larger program this is an example of how to keep a reliable count for something.

Calling answered 10/6, 2019 at 16:58 Comment(1)
This answer does not seem related to the question?Cordula

© 2022 - 2024 — McMap. All rights reserved.