Archived

This forum has been archived. Please start a new discussion on GitHub.

Sequence of 'unions'?

Is it possible to return a sequence of (simulated) union values?
I'm trying to do something along the lines of the following:

class SymValue { };
class ByteValue extends SymValue { byte byteval; };
class ShortValue extends SymValue { short shortval; };
class LongValue extends SymValue { long longval; };
class FloatValue extends SymValue { float floatval; };
class DoubleValue extends SymValue { double doubleval; };

struct SymDatum {
string name;
double rate;
short units;
SymValue* value;
};

sequence<string> SymNameSeq;
sequence<SymDatum> SymDataSeq;

// Return symbols matching 'symname'
class Source
{
nonmutating SymDataSeq SymQuery( string symname );
.
.
};

I've been having problems getting a test program for this to compile,
and just wanted to ask: is this even possible, or does the Slice-to-C++
mapping not permit such usage?

Comments

  • mes
    mes California
    Welcome!

    That approach is definitely supported, and is the recommended way to implement a union. I suspect your compile problems stem from your use of a proxy (SymValue*) in your struct, rather than an object instance. If I'm right, you need to remove the * from the value member.

    Take care,
    - Mark
  • > If I'm right, you need to remove the * from the value member.

    Thanks for the help, Marc. It was a bit confusing at first, but... it
    compiles as long as the right-hand of the last assignment below is a
    DoubleValuePtr:

    SmartNode::SymData symdata;
    SmartNode::DoubleValuePtr symvalue = new SmartNode::DoubleValue;
    symvalue->doubleval = 30.0;
    symdata.name = "VDM:RPM";
    symdata.value = symvalue; <-- this assignment

    I didn't realize that the left-hand side was of type 'SymValuePtr&'
    rather than 'SymValue&'.

    I'm still struggling with how to access the returned values, though.
    This code:

    cout << "Found the following matches:\n";
    for( SymDataSeq::const_iterator it = matches.begin();
    it != matches.end(); ++it )
    {
    cout << "\t" << (*it).name << " : Type = "
    << (*it).value->ice_id() << "\n";
    }

    prints out:

    Sending SymQuery for 'VDM:*'...
    Found the following matches:
    VDM:RPM : Type = ::SmartNode::DoubleValue
    VDM:RATE : Type = ::SmartNode::DoubleValue
    VDM:RATIO : Type = ::SmartNode::DoubleValue

    Which is just as it should be. Only the *type* is SymValuePtr&, so I've
    got to figure out how to convert a SymValuePtr& to a DoubleValuePtr& to
    access the member I'm looking for. I'm sure I'll hit upon the proper
    incantation Real Soon Now t.m. ... :-}

    Thanks again,

    - Dave

    P.S. Ice is *great*!
  • Originally posted by dwolfe5272
    [BI'm still struggling with how to access the returned values, though.
    This code:

    cout << "Found the following matches:\n";
    for( SymDataSeq::const_iterator it = matches.begin();
    it != matches.end(); ++it )
    {
    cout << "\t" << (*it).name << " : Type = "
    << (*it).value->ice_id() << "\n";
    }

    prints out:

    Sending SymQuery for 'VDM:*'...
    Found the following matches:
    VDM:RPM : Type = ::SmartNode::DoubleValue
    VDM:RATE : Type = ::SmartNode::DoubleValue
    VDM:RATIO : Type = ::SmartNode::DoubleValue

    Which is just as it should be. Only the *type* is SymValuePtr&, so I've
    got to figure out how to convert a SymValuePtr& to a DoubleValuePtr& to
    access the member I'm looking for. I'm sure I'll hit upon the proper
    incantation Real Soon Now t.m. ... :-}[/b]

    You need to use a dynamic cast:
    for( SymDataSeq::const_iterator it = matches.begin();
             it != matches.end(); ++it )
        {
            DoubleValuePtr p = DoubleValuePtr::dynamicCast(*it);
            if (p)
            {
                cout << p->doubleVal << "\n";
            }
        }
    

    See page 190 in the manual.

    Cheers,

    Michi.
    P.S. Ice is *great*!

    Glad you like it! :)
  • You need to use a dynamic cast...
    See page 190 in the manual.

    Thanks for the pointer--it just saved me a lot of time. I was trying to
    commit all sorts of horrible atrocities with dynamic_cast<> and C-style
    casts. I even attempted to call a (thankfully, non-existent) function
    called DoubleValue::checkedCast()--d'oh! :-% It's really quite nice,
    actually, that such rude hacks failed to compile! That seems to be a
    real strength of Ice: it seems to be kind of hard to do something really
    wrong and have the code compile properly.

    Thinks are working much, much better now... :-D
  • Originally posted by dwolfe5272
    I was trying to commit all sorts of horrible atrocities with dynamic_cast<> and C-style casts. I even attempted to call a (thankfully, non-existent) function called DoubleValue::checkedCast()--d'oh! :-%

    Yes, I would definitely call that a "horrible atrocity." Maximum penalty: writing insurance broking applications in BASIC and COBOL for five years ;)

    When using Ice, you never need to use a cast. If you want to do something and find that you can do it only with a cast, it is a sure-fire sign that you doing something you had better not :)
    It's really quite nice, actually, that such rude hacks failed to compile! That seems to be a real strength of Ice: it seems to be kind of hard to do something really wrong and have the code compile properly.

    Yes. A well-designed mapping uses the type system as a safety net: by carefully creating compatible and incompatible types as necessary, a lot of errors can be caught at compile time. This really is the main advantage of strongly-typed languages. Unfortunately, poor design (especially in C++) often ends up weakening the type system instead of strengthening it; C++ with its user-defined conversions unfortunately provides a lot of rope to hang yourself with. (The CORBA C++ mapping is a great example for how to unintentionally shoot holes through the static type system.)

    Cheers,

    Michi.
  • Originally posted by michi
    When using Ice, you never need to use a cast.

    Clarification: what I meant by this is that you never need to use a static_cast, reinterpret_cast, or a sledgehammer cast. But, of course, to get from a base to a derived, you have to use a dynamicCast.

    Cheers,

    Michi.