From: "Rolf Rabenseifner" Date: January 23, 2008 3:33:47 AM CST To: "Mailing list for discussion of MPI 2.1" Cc: mpi-21@XXXXXXXXXXXXX Subject: Re: [mpi-21] C++ predefined MPI handles, const, IN/INOUT/ OUT, etc. Reply-To: mpi-21@XXXXXXXXXXXXX Jeff, you are referencing to MPI-1.1, Sect. 2.2. The full Chapter 2 of MPI-1.1 is deprecated and substituted by the full Chapter 2 of MPI-2.0. In the substituting MPI-2.0 Sect. 2.3, there exist the following new paragraph: "MPI's use of IN, OUT and INOUT is intended to indicate to the user how an argument is to be used, but does not provide a rigorous classification that can be translated directly into all language bindings (e.g., INTENT in Fortran 90 bindings or const in C bindings). For instance, the ``constant'' MPI BOTTOM can usually be passed to OUT buffer arguments. Similarly, MPI STATUS IGNORE can be passed as the OUT status argument." My comments and alternative-proposal from Tue, 22 Jan 2008 17:29:51 was about this paragraph (updated text to reflect also the "IN" of "INOUT"): > An alternative-proposal would be to add a clarifying sentence in > Terms and Conventions, MPI-2.0 Sect. 2.5.1, page 9, line 7: > Handle arguments can be marked at INOUT to indicate that the handle > itself may be changed by the routine (e.g., in MPI_TYPE_COMMIT), > or to indicate that the object referenced by the handle already exists and > may be changed but the handle itself is kept unchanged > (e.g., MPI_TYPE_SET_NAME). Best regards Rolf On Tue, 22 Jan 2008 20:07:05 -0500 Jeff Squyres wrote:> The 3 proposals that I sent about C++ issues are both intertwined and > represent a very complex set of issues. > > Shorter version > =============== > > Does anyone know/remember why the "special case" for the definition of > OUT parameters exists in MPI-1:2.2? > > I ask because the C++ bindings were modeled off the IN/OUT/INOUT > designations of the language neutral bindings. MPI_COMM_SET_NAME (and > others) use the "special case" definition of the [IN]OUT designation > for the MPI communicator handle parameter. Two facts indicate that we > should either override this INOUT designation for the C++ binding (and > therefore make the method const) and/or revisit the "special case" > language in MPI-1:2.2: > > 1. The C binding does not allow the implementation to change the > handle value > 2. The following is a valid MPI code: > > MPI::Intracomm cxx_comm = MPI::COMM_WORLD; > cxx_comm.Set_name("foo"); > MPI::COMM_WORLD.Get_name(name, len); > cout << name << endl; > > The output will be "foo" even though we set the name on cxx_comm > and retrieved it from MPI::COMM_WORLD ***because the state changed on > the underlying MPI object, not the upper-level handles*** (the same is > true for error handlers). > > Hence, the Set_name() method should be const because the MPI handle > will not (and cannot) change. Similar arguments apply to keeping the > MPI predefined C++ handles as "const" (MPI::INT, etc.) -- their values > must never change during execution. It then follows that unless there > is a good reason for the "special case" language in MPI-1:2.2, it > should be removed. > > Longer version / more details > ============================= > > At the heart of the issue seems to be text from MPI-1:2.2 about the > definition of IN, OUT, and INOUT parameters to MPI functions. This > text was used to guide many of the decisions about the C++ bindings, > such as the const-ness (or not) of C++ methods and MPI predefined C++ > handles. The text states: > > ----- > * the call uses but does not update an argument marked IN > * the call may update an argument marked OUT > * the call both uses and updates an argument marked INOUT > > There is one special case -- if an argument is a handle to an opaque > object (these terms are defined in Section 2.4.1) and the object is > updated by the procedure call, then the argument is marked OUT. It is > marked this way even though the handle itself is not modified -- we > use the OUT attribute to denote that what the handle _references_ is > updated. > ----- > > The special case for the OUT definition is important because the C++ > bindings were created to mimic the IN, OUT, and INOUT behavior in a > language that is stricter than C and Fortran: C++ will fail to compile > if an application violates the defined semantics (which is a good > thing). > > *** The big question: does anyone know/remember why this special case > *** for the "OUT" definition exists? > > The special case seems to imply that *explicit* changes to MPI objects > should be marked as an [IN]OUT parameter (e.g., SET_NAME and > SET_ERRHANDLER). Apparently, *implicit* changes to the underlying MPI > object (such as MPI_ISEND) do not count / should be IN (i.e., many MPI > implementation *do* change the state either on the communicator or > something related to the communicator when a send or receive is > initiated, even though the communicator is an IN argument). > > But remember that MPI clearly states that the handle is separate from > the underlying MPI object. So why does the binding care if the back- > end object is updated? (regardless of whether the change to the > object is explicit or implicit) > > For example, the language-neutral binding for MPI_COMM_SET_NAME has > the communicator as an INOUT argument. This clearly falls within the > "special case" definition because the function semantics explicitly > change state on the underlying MPI object. > > But note that the C binding is "int MPI_Comm_set_name(MPI_Comm > comm, ...)". Notice that the comm is passed by value, not by > reference. So even though the language neutral binding called that > parameter INOUT, it's not possible for the MPI implementation to > change the value of the handle. > > My claim is that if we want to ensure that the C++ bindings match the > C bindings (i.e., that the implementation cannot change the value of > the MPI handle), then the method should be const (i.e., > cxx_comm.Set_name(...)) *because the handle value will not, and > ***cannot***, change*. > > Simply put: regardless of language or implementation, MPI handles must > have true handle semantics. For example: > > MPI::Intracomm cxx_comm = MPI::COMM_WORLD; > cxx_comm.Set_name("C++ r00l3z!"); > > MPI::COMM_WORLD.Get_name(name, len); > cout << name << endl; > > The above will output "C++ r00l3z!" because cxx_comm and > MPI::COMM_WORLD are handles referring to the same underlying > communicator. Hence, the only state that the handles have is whatever > refers to their back-end MPI object. Having Set_name() be const > keeps the *handle* const, not the underlying MPI object. > > Tying this all together: > > 1. cxx_comm.Set_name() *cannot* change state on the cxx_comm handle > because cxx_comm.Get_name() and MPI::COMM_WORLD.Get_name() must return > the same results (the same is true for error handlers). Hence, > regardless of the implementation of the C++ bindings, the handle value > cannot change. Therefore, this method (and all the others like it) > should be const. > > 2. As a related issue, if no one can remember why the "special case" > exists for OUT, then I think we should remove this text and then > change all those INOUT parameters for the functions I cited in my > earlier proposal to IN. This would make the C++ bindings consistent > with the IN/OUT/INOUT specifications of the language-neutral bindings. > > 3. All the MPI C++ predefined handles should be const for many of the > same reasons. Regardless of what happens to the underlying MPI > object, the value of the handle cannot ever change. This is > guaranteed by MPI-2:2.5.4 pages 10 lines 38-41: > > "All named constants, with the exceptions noted below for Fortran, can > be used in initialization expressions or assignments. These constants > do not change values during execution. Opaque objects accessed by > constant handles are defined and do not change value between MPI > initialization MPI_INIT and MPI completion MPI_FINALIZE." > > Hence, they should all be "const". > > ----- > > In short: C++ gives us stronger protections to ensure that > applications don't shoot themselves in the foot. If the MPI > predefined handles are const, then statements like "MPI::INT = > my_dtype;" will fail to compile. This is a Good Thing. > > The original C++ bindings tried to take advantage of const, but missed > a few points. Ballot two and one of the items in ballot 3 incorrectly > tried to fix these points by removing const in several places. That > "fixes" the problem, but removes many of the good qualities that we > can get in C++ with "const". So let's fix the real problem and leave > "const" in the C++ bindings. > > Are you confused yet? :-) > > -- > Jeff Squyres > Cisco Systems > > _______________________________________________ > mpi-21 mailing list > mpi-21@XXXXXXXXXXX > http://lists.cs.uiuc.edu/mailman/listinfo/mpi-21 Dr. Rolf Rabenseifner . . . . . . . . . .. email rabenseifner@XXXXXXX High Performance Computing Center (HLRS) . phone ++49(0)711/685-65530 University of Stuttgart . . . . . . . . .. fax ++49(0)711 / 685-65832 Head of Dpmt Parallel Computing . . . www.hlrs.de/people/rabenseifner Nobelstr. 19, D-70550 Stuttgart, Germany . (Office: Allmandring 30)