Newbie questions about Pliant

Newbie questions about Pliant

Strange problem

A destroy on an r-value is called before a cast from
r-value to l-value is made.
Message posted by maybe Boris Reitman on 2005/12/25 15:51:58
Happy Holidays :) !

I have a PerlList datatype that is returned by a function call,
and a PerlArray, to which a perllist is assigned. Here is an example,

...
  var PerlArray retval
  console "#before call"
  retval := perl test_retvalue "a" "b" "c"
  console "#after call"
...

The call (perl ...) returns an instance of PerlList, which must be 
assigned to retval of type PerlArray according to my cast function.
What happens is that the destroy method on perllist is called before
the cast occurs.  Here is the output of runnning above,

--8<------------------
#before callnow in clear, got size: 0
In destroy perllist 3
DEBUG2: dec(134765220)
DEBUG2: dec(134765232)
DEBUG2: dec(134765244)
in cast perllist -> perlarray
#after callok
--->8----------

Here is the cast and destroy code:

function destroy perllist
  arg_w PerlList perllist
  var Int size := perllist:list:size
  console "In destroy perllist " size eol
  if size <= 0
    return
  for (var Int index) 0 size-1
    var SV sv := perllist:list:index
    console "DEBUG2: dec(" address_to_int:(sv) ")" eol
    lperl_SvREFCNT_dec sv
...

function 'cast PerlArray' perllist -> perlarray
  arg PerlList perllist
  arg PerlArray perlarray
  implicit
  var SV sv
  var Int size := perllist:list:size  
  var Int count := 0
  var PerlScalar tmp
  perlarray av := lperl_newAV
  console "in cast perllist -> perlarray" eol
  if size <= 0
    return
  while count < size
    sv := perllist:list:count
    tmp _set sv
    perlarray:count := tmp
    lperl_SvREFCNT_inc sv
    count := count + 1

Shouldn't the order be reversed ? First cast, and then destroy ?

Thanks,
Boris
Message posted by hubert.tonneau on 2005/12/25 22:57:59
You have to define:

function copy src dest
  arg PerlList src ; arg_w PerlList dest

This is true for any non scalar data type you define. You have to define
'create' 'destroy' and 'copy' functions, except when naive implementation
is ok.
Message posted by maybe Boris Reitman on 2005/12/26 07:14:53
Do you mean 'build' instead of create ?  

I am observing an instance that the 'build' is never run
on a return value. Is this expected behaviour ? 

-----8<------------------
method a '' i -> scalar
  arg PerlArray a
  arg Int i
  arg PerlScalar scalar
  #scalar sv := perl_sv_undef
  if a:av <> null
    if i < a:size
      var Address sv_ptr := lperl_av_fetch a:av i 0
      if sv_ptr <> null
        scalar _set (sv_ptr map SV)
---->8------------------
If I uncomment the line "scalar sv := perl_sv_undef" above, 
my program works as needed.   This line is precisely 
what a build for PerlScalar should do:

----8<------------------
function build s
  arg_w PerlScalar s
  s:sv := perl_sv_undef
  console "In build scalar" eol

function create s
  arg_w PerlScalar s
  s:sv := perl_sv_undef
  console "In create scalar" eol
---->8------------------

However, a build function for it is not executed, at least not at the right 
time. Here is an excerpt of test code,

----8<------------------
  ...
  console "#BEFORE" eol
  is retval:0 "a"
  console "#AFTER" eol
  ...
---->8------------------

The running in the correct case (with line uncommented),
--8<---
#BEFORE
not ok #expected "a" but got ""
#AFTER
->8---

Runnnig in incorrect case (with line commented out)
--8<---
not ok #expected 2 but got 0
In build scalar
not ok #expected 2 but got 0
#BEFORE
not ok #expected "a" but got "c"
#AFTER
-->8--

The three output lines before "#BEFORE" are due to some earlier test code.
Notice that neither "build" nor "create" have been invoked between BEFORE 
and AFTER.  The perl scalar object is in fact initialized with a non undef
value.  Is this expected behaviour ? If yes, it is somewhat inconvenient.
I tried, for instance, running build explicitely on the object, but it gave me 
an error.

modified code to call build explicitely,
--8<------------------
method a '' i -> scalar
  arg PerlArray a
  arg Int i
  arg PerlScalar scalar
  #scalar sv := perl_sv_undef
  build scalar
  if a:av <> null
    if i < a:size
      var Address sv_ptr := lperl_av_fetch a:av i 0
      if sv_ptr <> null
        scalar _set (sv_ptr map SV)
-->8------------------

The error:
--8<------------------
Failed to compile build   (PerlScalar w)
  compile /pliantx/language/perl/types/array.pli (internals) 81 3
-->8------------------

So I don't have build called automatically, and calling 
it explicitely doesn't work for some reason. I don't understand why 
is it not compiling it. So once again, is the whole behaviour with build 
not being called by design. ?  Also what is this create function, 
it is never called for me.

Boris


Message posted by hubert.tonneau on 2005/12/26 10:42:59
You are right, it is 'build', not 'create'
It is always called automatically.

What is probably distrubing you is that when you write:
  method a '' i -> scalar
    arg Int i ; arg PerlArray a
then the 'build' method for 'PerlArray' will not be called each time you
call the '' method.
Pliant uses a different mechanism than C++
Basically, in Pliant:
  method a '' i -> scalar
    arg Int i ; arg PerlArray a
will be automatically turned to something like:
  method a '' i scalar
    arg Int i ; arg_w PerlArray a
So, the caller is responsible for providing a temporary 'PerlArray' variable,
and the caller will 'build' it at the beginning of the caller function, and
'destroy' it at the end of the caller funcion.
The key advantage is avoiding multiple 'build' and 'destroy' when the function
is called many times in a loop.

Also, when you write something like:
a := foo b
sometime it will be turned to:
foo b a
and sometime it will be turned to
foo b t
a := t
where t is an automatically created temporary variable.

Now, the last point is that you have to define 'build' before defining any
fonction that use the given data type as a all as opposed to just
accessing some of it's fields.
Message posted by maybe Boris Reitman on 2005/12/27 02:50:44
I think you have misunderstood my question.  My question was why
the build method is not run for a return value of type PerlScalar.

--8<------------------
method a '' i -> scalar
  arg PerlArray a
  arg Int i
  arg PerlScalar scalar  # <-- this variable has some junk inside it, 
                         #      instead of being at the state just after build
  #scalar sv := perl_sv_undef
  if a:av <> null
    if i < a:size
      var Address sv_ptr := lperl_av_fetch a:av i 0
      if sv_ptr <> null
        scalar _set (sv_ptr map SV)
-->8------------------

If I don't modify "scalar" in the body of the function (say, the "if a:av<>null" 
condition is false), should the variable "scalar" be initialized with a build method 
defined for it ?  This is the build method, defined earlier in the code,

----8<------------------
function build s
  arg_w PerlScalar s
  s:sv := perl_sv_undef
  console "In build scalar" eol
---->8------------------

and this is the definition of the PerlScalar type:

----8<------------------
alias SV Address from "/pliant/language/basic/safe.pli"

type PerlScalar
  field SV sv
  #field Int dummy
---->8------------------

I wonder if enabling "dummy" field will change things. I will test it.

Thanks,
Boris
Message posted by hubert.tonneau on 2005/12/27 10:12:18
There was some typo mistakes in my answer, but the general idea is still
valid: when you write:

method a '' i -> scalar
  arg PerlArray a
  arg Int i
  arg PerlScalar scalar

Pliant automatically turns it to:

method a '' i scalar
  arg PerlArray a
  arg Int i
  arg_w PerlScalar scalar

So there is no reason to have 'build' method for data type 'PerlScalar' called
within your '' function.
The 'scalar' variable is passed by the caller.

If 'build' method was not called at all within the entire program execution,
then it would be another story.


Message posted by maybe Boris Reitman on 2005/12/27 15:33:33
Ok. Why do I get a syntax error when I try to call "build scalar" explicitely ?
--8<------------------
method a '' i -> scalar
  arg PerlArray a
  arg Int i
  arg PerlScalar scalar
  build scalar  # <-- try to call build
  if a:av <> null
    if i < a:size
      var Address sv_ptr := lperl_av_fetch a:av i 0
      if sv_ptr <> null
        scalar _set (sv_ptr map SV)
-->8------------------

The error,
--8<------------------
Failed to compile build   (PerlScalar w)
  compile /pliantx/language/perl/types/array.pli (internals) 81 3
-->8------------------

The build method is defined in a module that current module includes, 
so it is available.

And alternatively, if I create a local variable to the function body, 
will it then be garruanteed for build to be called on it within the body ?

--8<------------------
method a '' i -> scalar
  arg PerlArray a
  arg Int i
  arg PerlScalar scalar # not in initial state.
  var PerlScalar dummy  # is build called for this one?
  scalar := dummy # copy ensures that scalar is at initial state.
  if a:av <> null
    if i < a:size
      var Address sv_ptr := lperl_av_fetch a:av i 0
      if sv_ptr <> null
        scalar _set (sv_ptr map SV)
-->8------------------

Thanks, 
Boris
Message posted by hubert.tonneau on 2005/12/27 15:38:49
If you want to have an explicit build, you have to write either:

  PerlScalar destroy_instance addressof:scalar # 'scalar' is alive, so we have to first destroy it
  PerlScalar build_instance addressof:scalar # before we can rebuild it

or:

  scalar := var PerlScalar empty # just copy an empty instance