VSIPL 1.6 RTF Avatar
  1. OMG Issue

VSIPL16 — Dangerous implicit conversions

  • Key: VSIPL16-18
  • Legacy Issue Number: 18216
  • Status: open  
  • Source: dpdx.net ( Brooks Moses)
  • Summary:

    This issue is copied from an internally-filed issue at Mentor that dates
    back to the early days of the specification. Since that time, some
    usage patterns have emerged that appear useful – most notably, the
    implicit use of a length_type when a Domain<1> is required. This
    particular case should either be preserved or additional overloads of
    the relevant functions should be added.

    However, in general this complaint is still quite relevant – for
    instance, we should not be implicitly converting a length_type value to
    a LU_solver object.

    Note that I have not edited this to account for any changes to the
    specification (either section numbers or normative changes) since the
    issue was initially submitted in 2005.

    In most cases, the resolution – adding an "explicit" keyword to many of
    these constructors – seems straightforward and obvious. Chances are
    very high that any existing code which is broken thereby was erroneous
    in the first place.

    Many of the constructors specified can take a single argument but are
    not declared "explicit". A complete list:

    Dense<D>(Domain<D> const&)
    const_Vector(Vector const&)

    • const_Vector<>(Vector const&)
      template <typename T0, typename Block0>
      Vector(Vector<T0, Block0> const&)
    • const_Matrix<>(Matrix const&)
      template <typename T0, typename Block0>
      Matrix(Matrix<T0, Block0> const&)
    • const_Tensor<>(Tensor const&)
      template <typename T0, typename Block0>
      Tensor(Tensor<T0, Block0> const&)
      lud<>(length_type) or LU_solver<>(length_type), see #29

    Of these, only the starred conversions are defensible, and even
    they will require some design adjustments. All the
    rest are a problem; most are fixable simply by adding "explicit".
    For the case of Domain<1>, this will require redesign of other
    components to restore convenient usage; perhaps similarly for some
    of the conversions from Block&.

    Also, in the requirements list 6.3, the line View(Block &) should be
    annotated to indicate that the conversion should not be implicit.

    To expand on why these implicit conversions are dangerous...

    First, implicit conversions from native numeric types are especially
    problematic because of the promiscuous conversions among those types,
    inherited from C, that occur even before calling the constructor.
    As a result, any numeric type, whether int, float, char, or bool,
    matches the constructor argument, and thus is accepted freely in
    place of the class type by any function that takes an argument of
    that type, regardless of whether it makes sense. These mistakes
    can be very hard to spot; sometimes it results from calling f(a,b)
    when f(b,a) was meant. (Functions declared to take numeric types
    can sometimes be made safer by overloading with another that takes
    a different, but acceptable, numeric type.)

    Second, implicit conversions of any kind provoke annoying compiler
    error messages complaining of ambiguities when more than one
    conversion path is possible. The more implicit conversions that
    are possible, the more frequently such ambiguities occur. The
    workaround for such an ambiguity is to add a cast to the exact
    type, but casts are themselves a source of errors, and besides
    obscuring the logic of the code, they eliminate the convenience
    the implicit conversion was supposed to provide.

    Third, in cases where one conversion path is favored by the compiler
    over another, the compiler may silently choose what the programmer
    would consider the wrong one.

    Fourth, template argument matching ignores conversions, making those
    that do work less conveniently useful than they may seem.

  • Reported: VSIPL++ 1.2 — Tue, 23 Oct 2012 04:00 GMT
  • Updated: Fri, 6 Mar 2015 20:57 GMT