Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Is a pointer to a view not a view?

    Hi all. I've run into something puzzling and perhaps of general interest.

    Within Mata, I set up a view X to a Stata variable "mpg" (guess which dataset!), and a pointer pX to the view X.

    If I change X[1,1] to some value, the first observation in mpg changes to that value. That's how views are supposed to work.

    But if I change *pX[1,1] to some value, then even though X[1,1] changes, the underlying Stata variable does NOT change. I can't work out why.

    The code below demonstrates (Stata 13.1):

    Code:
    mata: mata clear
    mata:
    void mymatafn_view(scalar s)
    {
        st_view(X, ., "mpg")
        X[1,1]        = s            // assign
        "Value of Mata variable X[1,1]:"
        X[1,1]                    // display
    }
    end
    
    mata:
    void mymatafn_pointer(scalar s)
    {
        st_view(X, ., "mpg")
        pX            = &X        // pointer
        *pX[1,1]    = s            // assign
        "Value of Mata variable *pX[1,1]:"
        *pX[1,1]                // display
        "Value of Mata variable X[1,1]:"
        X[1,1]                    // display
    }
    end
    
    sysuse auto, clear
    
    list mpg in 1/1
    
    mata: mymatafn_view(1000)
    list mpg in 1/1
    
    mata: mymatafn_pointer(2000)
    list mpg in 1/1
    which leads the following output:

    Code:
    . sysuse auto, clear
    (1978 Automobile Data)
    
    .
    . list mpg in 1/1
    
         +-----+
         | mpg |
         |-----|
      1. |  22 |
         +-----+
    
    .
    . mata: mymatafn_view(1000)
      Value of Mata variable X[1,1]:
      1000
    
    . list mpg in 1/1
    
         +------+
         |  mpg |
         |------|
      1. | 1000 |
         +------+
    
    .
    . mata: mymatafn_pointer(2000)
      Value of Mata variable *pX[1,1]:
      2000
      Value of Mata variable X[1,1]:
      2000
    
    . list mpg in 1/1
    
         +------+
         |  mpg |
         |------|
      1. | 1000 |
         +------+

    When I call the Mata function mymatafn_view(.), X[1,1] changes to 1000, and so does the first ob in the Stata variable mpg.

    But when I call the Mata function mymatafn_pointer(.), and *pX[1,1] changes to 2000, even though X[1,1] also changes to 2000, the first ob in mpg stays unchanged at 1000.

    Any ideas? This is of practical significance; I have an application where I want to pass around a pointer to a view, and have any changes made be reflected in the underlying Stata variable.
    Last edited by Mark Schaffer; 06 Aug 2014, 08:30.

  • #2
    Mata is binding on square brackets before the pointer is referenced.

    Change
    Code:
    *pX[1,1]
    to
    Code:
    (*pX)[1,1]

    Comment


    • #3
      Ha! It was that simple. Amazing. Thanks, Jeff!!

      Should I take a general lesson from this, namely that good/safe practice is to *always* surround pointer references with (.), to avoid exactly this problem? (And, come to think of it, is there a rationale for square brackets to bind in preference to pointer referencing?)

      Comment


      • #4
        Originally posted by Mark Schaffer View Post
        Ha! It was that simple. Amazing. Thanks, Jeff!!

        Should I take a general lesson from this, namely that good/safe practice is to *always* surround pointer references with (.), to avoid exactly this problem? (And, come to think of it, is there a rationale for square brackets to bind in preference to pointer referencing?)
        On the 1st question, there is analogy with C#, you can write typecasts using two syntaxes:
        Code:
        (boxplot)bp
        bp as boxplot
        Both are valid and differ in what happens when bp is not actually a pointer to a boxplot class object.
        However, when you want to address a member of bp, you do need parenthesis again:
        Code:
        ((boxplot)bp).scale
        (bp as boxplot).scale
        You just can't write it otherwise in the second case, (since you want to address a member of the bp object, not the boxplot class itself), in the first case it is easy to make a mistake. If you are working with a pointer on its own, you don't need the (.), but if you need something from inside the object that the pointer refers to, dereference the pointer first with ().

        On the 2nd question, the developers of StataCorp should answer. But I guess it is a matter of choice, similarly to the choice in operators precedence in (x AND y==1) : do you want to compute x AND y first? or check whether y is one first? This is a matter of convention: compare e.g. pascal vs c++. Personally I like to write x==1 or y==2 without having to write parentheses(x==1) or (y==2)

        Best, Sergiy Radyakin

        Comment

        Working...
        X