3

I have a matrix class in C++ and the constructor is as follows:

template <typename T> CMatrix<T>::CMatrix(unsigned int varrow,unsigned int varcolumn)
{
        //Lets set member variables
        this->m_row=varrow;this->m_column=varcolumn;

        //Create a place holder at heap
        m_matrix=new T[varrow*varcolumn];
        //
        unsigned int i=0;
        //
        //Default matrix All elements are zero

            for(i=0;i<varrow*varcolumn;i++)
            {
                    m_matrix[i]=T();
            }

        //
    }

I have implemented set and get methods as follows:

void SetCellValue(unsigned int row,unsigned int col,T value){ m_matrix[row*m_column+col]=value;}
T& GetCellValue(unsigned int row,unsigned int column) const{return m_matrix[row*m_column+column];}

The matrix class is accessible from Lua; however, the only way I can access to elements of matrix from Lua is, say if m is a matrix, m:GetValue or m:SetValue.

I want to know whether it is possible to access (set) matrix elements by a notation m[1,2] or maybe m(1,2) where m is a matrix, [1,2] is the element at first row and second column.

macroland
  • 973
  • 9
  • 27

1 Answers1

1

There are two basic issues. lua syntax, and lua semantics.

Syntax

As far as syntax goes, m(1,2) is definitely possible, if you use the __call metamethod of the userdata.

I don't think that m[1,2] is possible, I think that cannot be valid lua. You can use m[{1,2}] if you use the __index metamethod though.

Semantics

The basic issue is that lua, like javascript, java, and other languages that are not C++, makes primitive integers be value types rather than reference types.

So you can easily make m(1,2) return the correct integer, but if you want to write m(1,2) = 5, that's harder, because m(1,2) only returns a copy, not a reference.

In Java the (much maligned) solution is to use Boxing, where you wrap a primitive type in a class, in order to give it the correct (reference) semantics. The analogue here would be that you don't return an int, you return a userdata that wraps a reference to an int in your matrix.

In lua you usually avoid this by using the __index and __newindex metamethods. __index is called when you request a child value from a userdata, and __newindex is called when you assign a child value of a userdata. So no boxing is required, you can give it all whatever semantics you want.

The problem is that in this case, __index and __newindex will give you ugly syntax, you'll have to use m[{1,2}] and m[{1,2}] = 5 to get it to work that way.

Options

So, option (1) is, implement some kind of boxing for whatever type you have, and use the __call metamethod.

Option (2) is, just use __index and __newindex and get used to writing m[{1,2}].

Option (3) is, try to use a different syntax m[1][2]. Then you would want to make a new class that represents a row of the matrix, and make it be exposed to lua via m[1]. However that also adds some complexity, there are various reasons you wouldn't want to do this. (And you indicated in comments that you don't really want to do this.)

The nicest thing would be if they extended the lua language so that m[1,2] was just syntactic sugar for m[{1,2}] or something like that. But, I wouldn't hold my breath.

If it were me, and option (3) is out of the question, I guess I would pick option (2) and get used to it. Would like to see if someone knows an improvement to it.

Chris Beck
  • 15,614
  • 4
  • 51
  • 87
  • I never used LUA, but I am wondering if he couldnt just implement an `element& operator(int,int)` for his matrix class to get the desired behaviour – 463035818_is_not_an_ai Sep 18 '15 at 09:26
  • I tried the first option and it worked but as you said it is not working for `m(1,2)=5`. I was wondering if it is going to make sense to use nested metatables such as __call and __eq so that the previous expression can work. Your second proposal is a good one but I dont want to expose a `RowVector` to Lua and not sure how to do it without opening it to Lua – macroland Sep 18 '15 at 12:13
  • Is there a way to get the value on the right hand side of an assignment; for example I can get `m(1,2)` to work and if somehow I can read the value after `=` then it would have been easy to manipulate `m(1,2)=5`. – macroland Sep 23 '15 at 03:53
  • no, there isn't a way to do that in lua. lua does not have "copy assignment operators" like in C++. a simple assignment `a = b` is always going to just assign the value / make a reference. If you assign to an index of a table with a metatable, the assignment can be captured via `__newindex`, but that's it. (technically, `a = b` can be captured if the global table `_G` has a metatable. but `m(1,5) = b` cannot be captured, the left hand side is not an index of any table.) – Chris Beck Sep 23 '15 at 04:24
  • Since there is no more comment on this question I would like to accept yours which was comprehensive. – macroland Nov 16 '15 at 02:54