Skip to content

[Rcpp-devel] "expecting a string" and not finding it in a CharacterVector

15 messages · Kevin Ushey, Dirk Eddelbuettel, Davor Cubranic +1 more

#
I have a CharacterVector from which I try to extract an element and assign it to a std::string:

CharacterVector xs;
...
std::string x = as<std::string>(xs(0));

This throws exception: "expecting a string". Why? Looking with the debugger at "xs", this is what I see:

(gdb) print xs
$6 = (CharacterVector &) @0x7fff5fbfcca0: {
  <Rcpp::RObject> = {
    _vptr$RObject = 0x1061979d0, 
    m_sexp = 0x10582b618
  }, 
  <Rcpp::VectorBase<16,true,Rcpp::Vector<16> >> = {
    <Rcpp::traits::expands_to_logical__impl<16>> = {<No data fields>}, <No data fields>}, 
  <Rcpp::internal::eval_methods<16>> = {<No data fields>}, 
  members of Rcpp::Vector<16>: 
  cache = {
    p = 0x7fff5fbfcca0
  }
}

I've no idea how to poke any deeper and see what the actual R object in the first element of the vector is. Can anyone help with this?

This is with R 2.15.2 and Rcpp 0.10.2 on OS X 10.7.5. The code in question worked fine with Rcpp 0.10.0.

Davor
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20130207/ef265db2/attachment.html>
#
Hi Davor,

One trick to get around this is to 'as' the entire CharacterVector into a
std::vector< std::string >, and then index based off of that.

My guess is though, elements of CharacterVectors are 'const char*' s, so to
convert them to strings you might want to just use std::string constructor,
eg. std::string( xs(0) ).

-Kevin
On Thu, Feb 7, 2013 at 10:05 AM, Davor Cubranic <cubranic at stat.ubc.ca>wrote:

            
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20130207/94bc16da/attachment-0001.html>
#
On 2013-02-07, at 10:15 AM, Kevin Ushey wrote:

            
That used to work with 0.10.0, but when I upgraded this morning to 0.10.2, gives me the following compile error:

rcppdb.cpp:131: error: no matching function for call to 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(SEXPREC* const&)'
/usr/include/c++/4.2.1/bits/basic_string.tcc:233: note: candidates are: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(typename _Alloc::rebind<_CharT>::other::size_type, _CharT, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]
/usr/include/c++/4.2.1/bits/basic_string.tcc:226: note:                 std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]
/usr/include/c++/4.2.1/bits/basic_string.tcc:219: note:                 std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, typename _Alloc::rebind<_CharT>::other::size_type, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]
/usr/include/c++/4.2.1/bits/basic_string.tcc:208: note:                 std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&, typename _Alloc::rebind<_CharT>::other::size_type, typename _Alloc::rebind<_CharT>::other::size_type, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]
/usr/include/c++/4.2.1/bits/basic_string.tcc:197: note:                 std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&, typename _Alloc::rebind<_CharT>::other::size_type, typename _Alloc::rebind<_CharT>::other::size_type) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]
/usr/include/c++/4.2.1/bits/basic_string.tcc:183: note:                 std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]
/usr/include/c++/4.2.1/bits/basic_string.tcc:191: note:                 std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]
/usr/include/c++/4.2.1/bits/basic_string.h:2065: note:                 std::basic_string<_CharT, _Traits, _Alloc>::basic_string() [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]
make: *** [rcppdb.o] Error 1

Perhaps this is caused by the same bug, introduced somewhere post-0.10.0.

Davor
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20130207/f7ee7adc/attachment.html>
#
Davor, Kevin,

Allow to get into this intra-Vancouver exchange as I too dislike the sound of
"but this used to work"....  

A simple modifcation (see below) seems to do the trick:

R> sourceCpp("/tmp/davor.cpp")
R> getString(c("The", "quick", "brown", "fox"), 2)
[1] "brown"
R> getString(c("The", "quick", "brown", "fox"), 0)
[1] "The"
R> 

Here I do in fact go via char*. I too have the feeling that that didn't use
to be necessary --- but then "fear not" as we are currently getting better
string classes in Rcpp thanks to Romain (and to Hadley for funding).  So I
would just sit tight and wait things.  And maybe send us a new unit test for
two as the dozen or so we have for CharacterVector didn't catch this.

Dirk (hoping he understands what Davor was after in the first place...)


#include <Rcpp.h>

using namespace Rcpp;

// [[Rcpp::export]]
std::string getString(CharacterVector cv, int pos) {
  char *c = cv[pos];
  std::string s(c);
  return s;
}
#
I tracked this down to const-ness:

bar <- cxxfunction(signature(xs_="character"), plugin='Rcpp', body='
const CharacterVector xs(xs_);
const std::string x(xs(0));
Rcout << x << std::endl;')

fails with the compile error mentioned in my last message, while

foo <- cxxfunction(signature(xs_="character"), plugin='Rcpp', body='
CharacterVector xs(xs_);
std::string x(xs(0));
Rcout << x << std::endl;')

foo(month.abb)

works fine. I'll be happy to add a unit test to the package if the devs want it.

And to go back to my initial qustion: I'm still not sure why "as<std::string>" doesn't work:

baz <- cxxfunction(signature(xs_="character"), plugin='Rcpp', body='
CharacterVector xs(xs_);
std::string x = as<std::string>(xs(0));
Rcout << x << std::endl;')

baz(month.abb)

will throw "expecting a string".

Davor
On 2013-02-07, at 10:27 AM, Davor Cubranic wrote:

            
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20130207/780adafc/attachment.html>
#
Perhaps this will narrow down the 'why as seems to fail'. I'm looking at
the Rcpp 0.10.2 source. (hopefully I've got this right):

Rcpp's 'as' uses ::Rf_isString to check whether the item passed is a
string; or more specifically, a STRSXP. However, elements within a
CharacterVector seem to be of 'type' CHARSXP, and hence fail this test, and
throw that exception.

This is kind of surprising since I thought CharacterVectors / StringVectors
were defined as (high-level) containers for STRSXPs ? Certainly, that's
what we see in Rcpp/instantiation.h ...

Sample code:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
StringVector check( StringVector x ) {
  Rcout << "The type of x is: " << ::TYPEOF( x ) << std::endl;
  Rcout << "The type of x(0) is: " << ::TYPEOF( x(0) ) << std::endl;
  Rcout << "The integer associated with STRSXPs is: " << STRSXP <<
std::endl;
  Rcout << "The integer associated with CHARSXPs is: " << CHARSXP <<
std::endl;
  Rcout << "Is x a string?: " << ::Rf_isString(x) << std::endl;
  Rcout << "Is x(0) a string?: " << ::Rf_isString(x(0)) << std::endl;
  return x;
}

/*** R
check( c("a", "b", "c") )
*/

gives me

The type of x is: 16
The type of x(0) is: 9
The integer associated with STRSXPs is: 16
The integer associated with CHARSXPs is: 9
Is x a string?: 1
Is x(0) a string?: 0
[1] "a" "b" "c"

Perhaps someone can illuminate further...
-Kevin
On Thu, Feb 7, 2013 at 10:55 AM, Davor Cubranic <cubranic at stat.ubc.ca>wrote:

            
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20130207/f0cedcb3/attachment.html>
#
The version assigning an element of a const CharacterVector to a const 
std::string (named "bar" below) compiles and works fine in Rcpp 0.9.14, 
so the problem was introduced after that.

On the other hand, "as<std::string>" (function "baz") fails as in 
0.10.2, probably for the same reason Kevin identified in his last email 
(a check with ::Rf_isString).

Davor
On 13-02-07 10:55 AM, Davor Cubranic wrote:
#
On 13-02-07 07:24 PM, Davor Cubranic wrote:
To be more precise, it was introduced after 0.10.0 and before 0.10.1.

Davor
#
Thanks. I will fix it. 

Romain

Le 8 f?vr. 2013 ? 05:28, Davor Cubranic <cubranic at stat.ubc.ca> a ?crit :
#
That fixed just the runtime fault in "as", right? Or did it somehow also take care of ctor for const string from an element of const CharacterVector?

Davor
On 2013-02-08, at 6:10 AM, Dirk Eddelbuettel <edd at debian.org> wrote:

            
#
On 8 February 2013 at 20:58, Davor Cubranic wrote:
| That fixed just the runtime fault in "as", right? Or did it somehow also take care of ctor for const string from an element of const CharacterVector?

The former:

R> sourceCpp("/tmp/davor.cpp")
R> cv <- c("The", "quick", "brown", "fox")
R> getString1(cv, 2)
[1] "brown"
R> getString2(cv, 2)
[1] "brown"
R> 

using 


#include <Rcpp.h>

using namespace Rcpp;

// [[Rcpp::export]]
std::string getString1(CharacterVector cv, int pos) {
  char *c = cv[pos];
  std::string s(c);
  return s;
}

// [[Rcpp::export]]
std::string getString2(CharacterVector cv, int pos) {
  std::string s(cv[pos]);
  return s;
}


Variants with 'const CharacterVector' still fail. That would involve a lot
more work to extend as<> to permit them.   And at the end of the day the SEXP
is always a pointer into R's data so I am not really sure we really can
assure const correctness all the way.

Dirk
#
On 13-02-09 05:06 AM, Dirk Eddelbuettel wrote:
>
I didn't mean "const as<>", but a const version of 
CharacterVector::operator[] that can be used in a const string's 
constructor, as it did before 0.10.1.

Davor
#
Right. I see what you mean. If it does bot disturbe anything else, i should be able to bring it back. 

Romain


Le 10 f?vr. 2013 ? 04:54, Davor Cubranic <cubranic at stat.ubc.ca> a ?crit :
1 day later
#
Thank you. I'll send you unit tests for both "as" and "const ctor". 

Davor
On 2013-02-10, at 6:06 AM, Romain Francois <romain at r-enthusiasts.com> wrote: