These are chat archives for symengine/symengine

19th
Jul 2015
Isuru Fernando
@isuruf
Jul 19 2015 06:53
@bluescarni, mingw-w64 is a very good compiler, didn't give any complaints.
@certik, I was able to compile symengine with mingw-w64 with gmp builds from mingw, but fails at linking time. We need to resolve #478
Francesco Biscani
@bluescarni
Jul 19 2015 12:45
@isuruf nice to hear, I like mingw-w64 a lot for windows work
I left some comments at #478 about my experiences with mpz ints and move semantics, maybe you can find it useful
Sumith Kulal
@Sumith1896
Jul 19 2015 13:20
@shivamvats Best solution now is to install in home or other directory if you don't want to make install, then include that
Isuru Fernando
@isuruf
Jul 19 2015 14:44
@bluescarni, I was able to compile GMP with MinGW-w64 andMSYS (Package from MinGW). Everything went fine. I can copy all the dllsand then reuse it later. That's okay right?
Francesco Biscani
@bluescarni
Jul 19 2015 14:50
it should be ok yes... just remember that there might be some dependency on MinGW dlls. You can check the dependency between dlls using something like this: http://www.dependencywalker.com/
if that's the case then you need to ship mingw.dll or whatever it is called with your binaries
maybe there's also some dependency on GCC libs, I am not sure if that applies only to C++ libraries or C as well
Isuru Fernando
@isuruf
Jul 19 2015 14:51
Yes. Those dlls will be there when we test on appveyor. Just GMP won't be built every time.
Francesco Biscani
@bluescarni
Jul 19 2015 14:51
in any case the dependency checker will tell you
ok sounds good, it should work
Isuru Fernando
@isuruf
Jul 19 2015 15:24
For Python, I used a patched libpython27.a
Works fine
Francesco Biscani
@bluescarni
Jul 19 2015 15:32
64 bit?
Isuru Fernando
@isuruf
Jul 19 2015 15:33
yes
Francesco Biscani
@bluescarni
Jul 19 2015 15:33
oh cool.. where did you find it?
Francesco Biscani
@bluescarni
Jul 19 2015 15:36
ah ok nice
I wasn't aware that guy also had the mingw versions
Isuru Fernando
@isuruf
Jul 19 2015 15:39
It's quite an extensive collection. Must have taken lots of work
We are installing symengine into C:\Program Files (x86) though
Ondřej Čertík
@certik
Jul 19 2015 16:57
@isuruf are you downloading the mingw64 compiler yourself?
Isuru Fernando
@isuruf
Jul 19 2015 16:57
yes
Ondřej Čertík
@certik
Jul 19 2015 16:57
I see. So AppVeyor only ships 32 bit versions?
Isuru Fernando
@isuruf
Jul 19 2015 16:57
yes
Ondřej Čertík
@certik
Jul 19 2015 16:57
How big is the binary?
Isuru Fernando
@isuruf
Jul 19 2015 16:58
50.3MB
Ondřej Čertík
@certik
Jul 19 2015 16:58
Ok, I would definitely keep it in a binaries branch for now.
Otherwise the git master will quickly become big I think if we keep such big binaries in there.
@bluescarni thanks for your comment in #478. For things like a+b+c, what stops us to get a raw pointer out of our class, and use the GMP primitives directly? Then we can control exactly what will get allocated and it should be as fast as the mpz_class with expression templates. Or am I missing something?
And as a benefit, you can use mpz_addmul() in the same way without a hassle, so it will actually even be faster than the current mpz_class, as you mentioned.
Isuru Fernando
@isuruf
Jul 19 2015 17:03
symengine/dependencies#2
Ondřej Čertík
@certik
Jul 19 2015 17:03
You can merge it.
Isuru Fernando
@isuruf
Jul 19 2015 17:04
Is there a CMake way to figure out MinGW-w64 from MinGW?
Ondřej Čertík
@certik
Jul 19 2015 17:05
For mingw, we are using the "single configuration" makefiles, is that right? (as opposed to the multi-configuration MSVC build files, where you decide between Debug/Release once you build, not at cmake time)
Isuru Fernando
@isuruf
Jul 19 2015 17:06
Yes
Ondřej Čertík
@certik
Jul 19 2015 17:06
It's actually not relevant here. I noticed that if I want to select a MSVC version, I have to use the proper -G thing.
But for mingw, you can select it using CMAKE_CXX_COMPILER I think.
Isuru Fernando
@isuruf
Jul 19 2015 17:07
For MinGW and MinGW-w64, what I do is cmake -G "MinGW Makefiles"
Ondřej Čertík
@certik
Jul 19 2015 17:07
I still think you can select the compiler using the flag.
Isuru Fernando
@isuruf
Jul 19 2015 17:07
I want to add a new flag for MinGW-w64, but only for MinGW-w64
Ondřej Čertík
@certik
Jul 19 2015 17:08
The other option is using CXX=/path/to/compiler, that's actually the easiest.
On linux, that's what I use all the time.
Isuru Fernando
@isuruf
Jul 19 2015 17:08
I think I confused you.
It's not about selecting the compiler.
It's about checking which compiler is used in CMake
Ondřej Čertík
@certik
Jul 19 2015 17:09
Ah
Isuru Fernando
@isuruf
Jul 19 2015 17:09
For GCC and Clang, I could check CMAKE_CXX_COMPILER_ID and for MinGW I could check MinGW, but it is the same for MinGW-w64 as well.
Ondřej Čertík
@certik
Jul 19 2015 17:09
So I wasn't able to find good documentation for that. We mostly use CMAKE_CXX_COMPILER_ID which works great.
but for MSVC, we just use the MSVC variable.
and for MinGW, we use MinGW.
Isuru Fernando
@isuruf
Jul 19 2015 17:10
Yes. MINGW variable is present for both MinGW and MinGW-w64
Ondřej Čertík
@certik
Jul 19 2015 17:10
so it's not very consistent. We should print CMAKE_CXX_COMPILER_ID during our cmake summary section.
Then you can look up what CMake has to say about it.
Isuru Fernando
@isuruf
Jul 19 2015 17:11
CMAKE_CXX_COMPILER_ID is GNU for MinGW
Ondřej Čertík
@certik
Jul 19 2015 17:11
Perhaps there is a difference between 32 and 64 bit mingw.
Hm.
Were you able to find some documentation about the MSVC and MinGW variables?
Ondřej Čertík
@certik
Jul 19 2015 17:14
I see, so for MSVC we should just use CMAKE_CXX_COMPILER_ID.
Why do we sometimes use STREQUAL and sometimes MATCHES?
I vaguely remember there was some issue with Clang?
Isuru Fernando
@isuruf
Jul 19 2015 17:15
STREQUAL is like ==
MATCHES is like contains
Ondřej Čertík
@certik
Jul 19 2015 17:15
I understand that, but why would we use matches?
Isuru Fernando
@isuruf
Jul 19 2015 17:15
Clang, AppleClang
Ondřej Čertík
@certik
Jul 19 2015 17:16
Ah, I see.
Francesco Biscani
@bluescarni
Jul 19 2015 17:17
MinGW-w64 works also for 32 bit, I would suggest to just use that as MinGW version
Isuru Fernando
@isuruf
Jul 19 2015 17:18
Problem is I want to give -D MS_WIN64 for python wrappers
Ondřej Čertík
@certik
Jul 19 2015 17:18
@bluescarni how do you tell mingw64 to compile for 32 bits?
Francesco Biscani
@bluescarni
Jul 19 2015 17:18
Not sure that I follow... you are building 32 and 64 bit versions in the same appveyor run?
Ondřej Čertík
@certik
Jul 19 2015 17:18
No, we are not.
@bluescarni is this the home for mingw64: http://sourceforge.net/projects/mingw-w64/
Francesco Biscani
@bluescarni
Jul 19 2015 17:19
I think you can use the -m32 flag, not sure... I'd just spawn a 32 bit Windows VM and then it would be forced to do 32bit builds I suppose
Ondřej Čertík
@certik
Jul 19 2015 17:19
AppVeyor only has one VM.
Francesco Biscani
@bluescarni
Jul 19 2015 17:19
yes... but there are multiple builds available depending on what you need
ok.. it is a 64bit VM then?
Ondřej Čertík
@certik
Jul 19 2015 17:20
I think it is, but I am not sure.
Francesco Biscani
@bluescarni
Jul 19 2015 17:20
this seems to be better as a home page
sourceforge has become fishy unfortunately
I use the mingw-builds package previously, I like that one as it is minimal
it has a .exe autoinstaller, might not be what you want for appveyor though... unless you install it locally and then package the files, host them and pull them from the appveyor build
Isuru Fernando
@isuruf
Jul 19 2015 17:23
@bluescarni, btw, MinGW-w64 also has the hypot issue where including math.h gives an error about hypot not being defined
Francesco Biscani
@bluescarni
Jul 19 2015 17:24
yes that is a Python issue, IIRC it is solvable by forcing the include order in your files
let me check
https://github.com/bluescarni/piranha/blob/master/pyranha/python_includes.hpp that's how I solved it without adding extra definitions
so I just include python_includes.hpp whenever I need to include Python.h
Isuru Fernando
@isuruf
Jul 19 2015 17:26
Our python files are generated by Cython and it include Python.h at the top, but the issue I mentioned is there on files without Python.h
Ondřej Čertík
@certik
Jul 19 2015 17:27
@bluescarni what do you think of my comment above: https://gitter.im/sympy/symengine?at=55abd72b071d142f4778cb3c
Francesco Biscani
@bluescarni
Jul 19 2015 17:27
@isuruf I see... probably it's more about including cmath first then maybe?
Isuru Fernando
@isuruf
Jul 19 2015 17:27
yes
Francesco Biscani
@bluescarni
Jul 19 2015 17:28
@certik I am not sure I understand exactly what you mean... does it involve rvalue references?
Where you have to call get_mpfr_t to do anything.
So the class is simple and short, but it seems to me it is as performing as the best class that you can write in C++, simply because you just call the MPFR (in this case) primitives by hand.
The class just manages the memory, so you don't get leaks, but otherwise it doesn't do anything else.
Ondřej Čertík
@certik
Jul 19 2015 17:50
@bluescarni.
Francesco Biscani
@bluescarni
Jul 19 2015 18:03
@certik yes but then you lose the convenience and generality of operator overloading
the convenience argument might not be that compelling
the generality might be though...
if you have a generic algorithm that works with operators, it will probably work equally well on doubles, ints, etc.
and you can write it down as a template
but if your arithmetic operations are implemented with a custom API, you suddenly have to write another version of the same algorithm which differs only in the implementation of basic arithmetics via GMP API
so pros and cons, I wish there was a universal solution
my approach so far has been to keep things general and then make things ugly only when needed, preferably after profiling
Isuru Fernando
@isuruf
Jul 19 2015 18:18
@certik, #552, is okay to be merged right?
Ondřej Čertík
@certik
Jul 19 2015 18:31
yes
Ondřej Čertík
@certik
Jul 19 2015 18:38
@bluescarni cannot you write your algorithm using operators like += or + (with two operands) so that it performs equally fast with doubles as well as my "dumb" class?
For example, z=a+b+c would be written as z=a+b; z += c or something like that.
That seems like a reasonable middle ground --- my dumb class is super simple, easy to read/debug/maintain, and very very fast. And I just need to write the algorithm so that it translates directly to the underlying GMP primitives without extra allocation.
We went over our code, and the most complicated case that we were able to find is: https://github.com/sympy/symengine/issues/478#issuecomment-116731666, which seem very easy to workaround.
Francesco Biscani
@bluescarni
Jul 19 2015 18:44
So you mean like normal operator overloading? I understood you wanted just the mpz_t API
that would work ok yes
Ondřej Čertík
@certik
Jul 19 2015 18:45
Well, currently our MPFR class requires to use the low level api, but it's easy to implement the usual operator overloading.
Francesco Biscani
@bluescarni
Jul 19 2015 18:45
right... it also depends on the specifics though
for instance mpz_t addition is fastest when implemented in-place
Ondřej Čertík
@certik
Jul 19 2015 18:45
Like +=?
Francesco Biscani
@bluescarni
Jul 19 2015 18:46
but multiplication is faster if you do mul(a,b,c)
yes
mul works best if you already have a return value ready, separate from the input value
Ondřej Čertík
@certik
Jul 19 2015 18:47
So mul works best if you do a = b + c, as long as "a" is ready?
While add works best if you do a = b; a+=c?
Francesco Biscani
@bluescarni
Jul 19 2015 18:47
yes
I am trying to dig out the reference
it's somewhere on the GMP website
Ondřej Čertík
@certik
Jul 19 2015 18:47
So for add, it's easy to use our dumb class, for mul it looks like we can't use operator overloading, or can we?
you can and in my opinion it's worth it, until you measure the performance impact
the page above talks about a "slight" performance penalty
under "In-Place Operations"
Ondřej Čertík
@certik
Jul 19 2015 18:53
if we use piranha::integer, what's the best way to write the algorithm then?
as z = a + b + c, or z =a +b, z+= c
or perhaps z = a; z += b; z += c
does it matter for machine integers?
Francesco Biscani
@bluescarni
Jul 19 2015 18:54
as long as the operands are small I don't think there will be much of a difference
Ondřej Čertík
@certik
Jul 19 2015 18:56
I see.
It seems that if you really care about performance, using the GMP primitives in the correct way (per the link you said) is best, because you can ensure that things will be fast.
Francesco Biscani
@bluescarni
Jul 19 2015 18:57
I would not over optimise it in general... 99% it will be drowned into other bigger performance concerns
Ondřej Čertík
@certik
Jul 19 2015 18:58
in piranha::integer, do you care about this, or do you just create a temporary for things like z = a+b+c?
Francesco Biscani
@bluescarni
Jul 19 2015 18:58
it matters in things like poly multiplication, but that's why there is the addmul() primitive
just temporaries, in the same way you would have temporaries using doubles or longs
Ondřej Čertík
@certik
Jul 19 2015 18:59
so operator+ returns a piranha::integer, that had to call mpz_init?
Francesco Biscani
@bluescarni
Jul 19 2015 19:00
not necessary, if it is a small integer there will be no calls to the GMP API
Ondřej Čertík
@certik
Jul 19 2015 19:01
yes, for large integers.
Isuru Fernando
@isuruf
Jul 19 2015 19:01
@certik
sympy/symengine#553
symengine/dependencies#3
Francesco Biscani
@bluescarni
Jul 19 2015 19:01
yes for large integers that's the case
Ondřej Čertík
@certik
Jul 19 2015 19:01
i.e. if you do z = a+b+c+d+..., do you need to call mpz_init many times? as opposed to internally rewriting it as z=a; z+=b, z+=c, z+=d, .... which only requires to call mpz_init once?
Francesco Biscani
@bluescarni
Jul 19 2015 19:02
yes that's correct
Ondřej Čertík
@certik
Jul 19 2015 19:02
and you also have to call mpz_clear many times too...
As you said, I think that's fine for bigger operands, as long as you use machine ints.
Francesco Biscani
@bluescarni
Jul 19 2015 19:03
the old integer class (without small value optimisation) used to require a single allocation
Ondřej Čertík
@certik
Jul 19 2015 19:03
Right.
Francesco Biscani
@bluescarni
Jul 19 2015 19:04
it would reuse the storage of the temporaries
Ondřej Čertík
@certik
Jul 19 2015 19:04
Right.
Francesco Biscani
@bluescarni
Jul 19 2015 19:04
I could re-implement that logic but I see no compelling reason at the moment
and the class is complicated enough already
but I'd go for some expression templates if they ever get around making them play nicely with the type system
Ondřej Čertík
@certik
Jul 19 2015 19:05
You know, it seems that our dumb class can just do what piranha::integer does (without the small int optimization) and one can always use the GMP primitives or rewrite things using +=, if the extra allocation matters.
Francesco Biscani
@bluescarni
Jul 19 2015 19:05
yes I agree
you can always use the GMP api when speed matters
Ondřej Čertík
@certik
Jul 19 2015 19:06
My general philosophy is that I want to keep the code as simple as possible, without sacrificing performance. I don't want to do expression templates, as that's complicated.
The price is to use GMP primitives if the speed is an issue.
But it's also very explicit, so I actually kind of like this.
For performance critical routine, I think it's ok to be very explicit.
(And less general)
Francesco Biscani
@bluescarni
Jul 19 2015 19:08
yeah I agree
I don't see why you couldn't implement operators and also the mpz_t() getter, they can coexist
Ondřej Čertík
@certik
Jul 19 2015 19:08
right. Even mpz_class has it.
I wanted to implement Flint style small integer optimization and compare against piranha::integer
as we discussed.
I would like to know how each performs in various circumstances.
Francesco Biscani
@bluescarni
Jul 19 2015 19:10
right... it's gonna be much better than Piranha for single limb, I would expect
Ondřej Čertík
@certik
Jul 19 2015 19:11
We can add Piranha's methods, so that it can be used in Piranha as well, so that we can benchmark it easily on some of your benchmarks.
Francesco Biscani
@bluescarni
Jul 19 2015 19:11
yup, that would be interesting
I did some tests in the past, but all my big poly multiplication benchmarks would need more than one limb and so FLINT would perform similar or worse than GMP
as far as I remember at least
Ondřej Čertík
@certik
Jul 19 2015 19:12
that's because FLINT needs to allocate the mpz_t on heap and point to it all the time?
while piranha::integer stores the mpz_t structure by value?
Francesco Biscani
@bluescarni
Jul 19 2015 19:14
yes I think that was one of the reasons.. there's an extra redirection layer
Ondřej Čertík
@certik
Jul 19 2015 19:14
redirection and also allocation
Francesco Biscani
@bluescarni
Jul 19 2015 19:15
yes indeed
these things matter a lot in computations that are memory bound
Ondřej Čertík
@certik
Jul 19 2015 19:16
In Flint, you need to move the raw pointer around (8 bytes), and then still allocate the mpz_t, while in Piranha you only have to allocate piranha::integer (24 bytes I think).
Francesco Biscani
@bluescarni
Jul 19 2015 19:16
probably not so visible in the fateman benchmarks
yes that is correct
it depends a lot which use case you want to optimise... if you just expect to do most of the compuations in a machine integer, but you just want to make sure you don't overflow, FLINT is better (portability concerns aside)
Ondřej Čertík
@certik
Jul 19 2015 19:17
The way I see it is that we should have couple of these classes and just have them all.
And let the user choose.
It seems each of these classes has pros and cons.
Francesco Biscani
@bluescarni
Jul 19 2015 19:19
yes indeed, it's not something easy to solve universally, especially if you want performance
there's also the possibility a future C++ standard will come with a multiprecision integer
Ondřej Čertík
@certik
Jul 19 2015 19:19
Indeed, they might.
How would they implement it though?
As a c++ type like "int"?
that's a proposal
no as a class
I mean, it will be a std class
not a builtin type
Ondřej Čertík
@certik
Jul 19 2015 19:20
Ok. What's their idea how to handle some of the issues we discussed above?
Francesco Biscani
@bluescarni
Jul 19 2015 19:21
it's the C++ standard, so it is pretty vague... they describe the interface but they leave out the implementation details
Ondřej Čertík
@certik
Jul 19 2015 19:22
But does the interface allow all of the designs that we talked about above?
Or does it restrict us.
Francesco Biscani
@bluescarni
Jul 19 2015 19:22
one thing they are making sure is that it can be implemented with expression templates, which I am actually trying to convince them not to :)
no I don't think so, it is basically going to behave like a builtin
Ondřej Čertík
@certik
Jul 19 2015 19:23
What would you recommend instead of expression templates?
Francesco Biscani
@bluescarni
Jul 19 2015 19:24
I would recommend them to add a mechanism to disable them, should the user not want them
consider what happens when one writes:
auto a = b + c;
which is pretty much idiomatic in C++11
if b and c are big ints, a will not necessarily be
if it uses expr. template, a will be an implementation-defined struct convertible to bigint
so only this will work:
bigint a = b + c;
and it's not even the behaviour of standard integral types (int + int is always an int)
Ondřej Čertík
@certik
Jul 19 2015 19:27
Right, exactly.
Francesco Biscani
@bluescarni
Jul 19 2015 19:27
so apparently they are thinking about adding a new operator to the language :)
operator auto
which essentially allow to customise to what type a class deduces to in those contexts where the type has to be deduced from an expression
but it's all hypothetical at the moment
Ondřej Čertík
@certik
Jul 19 2015 19:29
What is your view on using raw pointers? in SymEngine we don't use any raw pointers, just RCP and Ptr. The Ptr should be as fast as raw pointers, but it's Debug time checked so you get an exception if it becomes dangling or null. I really like this design, but I don't understand why not more people use it. Instead, people still seem to use raw pointers for non-owning relationships.
Francesco Biscani
@bluescarni
Jul 19 2015 19:30
I agree with you, there's just a lot of inertia and a lot of ingrained "truths" that people stick to out of habit
I think one should call new rarely and never delete in user code
Ondřej Čertík
@certik
Jul 19 2015 19:31
I actually think one should never call new nor delete, and just use make_shared or make_unique.
(Unless you are implementing a low level data structure, in that case maybe it's needed, but you just wrap it up, so that the rest of the code doesn't see it.)
But I think most C++ people already agree with this. But they still recommend to use raw non-owning pointers.
There is an observer_ptr proposal for C++, which is essentially our Ptr. Then the std::shared_ptr needs to have a method like .ptr() that returns a Ptr to the object, that's Debug time checked.
Francesco Biscani
@bluescarni
Jul 19 2015 19:33
it depends what you are doing with the raw pointers though... if it is just a reference to some data is fine... for instance if you want to store a vector of pointers and sort those instead of the original data
that's perfectly fine
Ondřej Čertík
@certik
Jul 19 2015 19:33
You can do the same with our Ptr.
With raw pointers, if somebody modifies the code later and the objects go out of scope, then they become dangling. While with Ptr, you get an exception in Debug mode.
Francesco Biscani
@bluescarni
Jul 19 2015 19:34
yes you need to be in a context where you have a clear understanding of the lifetime of the object
Ondřej Čertík
@certik
Jul 19 2015 19:35
Exactly. But with Ptr, you do not need to worry about this at all. Whatever you do, it's safe in Debug mode.
Francesco Biscani
@bluescarni
Jul 19 2015 19:35
to be honest the whole pointer thing in C++ is an unfortunate consequence of how polymorphism has been traditionally implemented
Ondřej Čertík
@certik
Jul 19 2015 19:35
The difference is just std::vector<A*> vs std::vector<Ptr<A>>
Francesco Biscani
@bluescarni
Jul 19 2015 19:36
if you want polymorphic behaviour in C++, you need to start thinking about pointer semantics, which is insane because the two concepts share nothing in common, in principle
Ondřej Čertík
@certik
Jul 19 2015 19:36
True.
Francesco Biscani
@bluescarni
Jul 19 2015 19:36
there's a solution today, but it's new stuff and not really widely adopted
Ondřej Čertík
@certik
Jul 19 2015 19:37
What's the solution?
Francesco Biscani
@bluescarni
Jul 19 2015 19:37
it's called type erasure.. essentially you can use it to achieve polymorphic behaviour without ever thinking about pointers in user code
Ondřej Čertík
@certik
Jul 19 2015 19:37
I've heard about it, but forgot what it is.
Francesco Biscani
@bluescarni
Jul 19 2015 19:38
you just use value semantics
Ondřej Čertík
@certik
Jul 19 2015 19:38
But even with that I think you still need pointers for just pointing to objects like sorting, or just referencing them, don't you?
Francesco Biscani
@bluescarni
Jul 19 2015 19:38
there a nice presentation, let me see
possibly, although std::sort does use move semantics so it should be fast already for most use cases without doing indirect sorting
Ondřej Čertík
@certik
Jul 19 2015 19:39
What is your opinion about how to return values in arguments of a function? Do you prefer to use references, like void f(int in_arg, int &out_arg), or pointers (like the Google C++ standard) void f(int in_arg, int *out_arg)?
Francesco Biscani
@bluescarni
Jul 19 2015 19:40
I prefer to just return by value unless absolutely necessary
Ondřej Čertík
@certik
Jul 19 2015 19:40
So you do int f(int in_arg)?
Francesco Biscani
@bluescarni
Jul 19 2015 19:42
yep, unless in very few places in low-level code
otherwise I prefer references over pointers generally, unless I need to allow for null pointers
Ondřej Čertík
@certik
Jul 19 2015 19:42
What do you think of std::experimental::optional? It could be used for optional arguments instead of raw pointers, but I am a bit worried that the thing is larger than just 8 bytes...
And you return more than 1 value using std::pair or std::tuple?
Francesco Biscani
@bluescarni
Jul 19 2015 19:45
I haven't really used optional so far, so I have no opinions... pair if I am certain it's 2 values, tuple for more generality
Ondřej Čertík
@certik
Jul 19 2015 19:45
I see.
Francesco Biscani
@bluescarni
Jul 19 2015 19:45
to have an idea about type erasure, consider what you can do with std::function
Ondřej Čertík
@certik
Jul 19 2015 19:46
I use std::function, it's plain magic, but it can accept a lambda or a C function.
Francesco Biscani
@bluescarni
Jul 19 2015 19:46
you can construct it with any callable object, including function pointers, functors, etc. and then later you can call the object stored within
yes exactly... it's a bit like you defined a base class with a call operator right?
a bit as if the object you used for construction derived from this base class
Ondřej Čertík
@certik
Jul 19 2015 19:47
Exactly.
I have no idea how it works though.
Francesco Biscani
@bluescarni
Jul 19 2015 19:47
but there's no OO programming, at least visibly :)
basically you can define a "box" in which you can store all objects which expose a certain interface
they don't need to be related by OO relationships
and you don't need pointers to manipulate this "box"
just value semantics
Ondřej Čertík
@certik
Jul 19 2015 19:49
That's the way to go, for sure.
Could I use this for SymEngine::Basic and subclasses?
Francesco Biscani
@bluescarni
Jul 19 2015 19:49
yeah it looks really powerful
I bet so yes
I was trying to find a very nice presentation I saw about type erasure
Ondřej Čertík
@certik
Jul 19 2015 19:50
How can I store those in a vector? That's where I currently need to use RCP (or at least Ptr)?
Francesco Biscani
@bluescarni
Jul 19 2015 19:51
they have value semantics
Ondřej Čertík
@certik
Jul 19 2015 19:51
I can do std::vector<RCP<const Basic>>, but not std::vector<const Basic>.
Francesco Biscani
@bluescarni
Jul 19 2015 19:51
so you just store them as you would store an int
Ondřej Čertík
@certik
Jul 19 2015 19:51
But how does the class know the proper size?
Francesco Biscani
@bluescarni
Jul 19 2015 19:51
it does not, internally it uses pointers, but it is hidden from the user
it's the same price you'd pay with pointer semantics really
Ondřej Čertík
@certik
Jul 19 2015 19:52
So the size of the box is just a pointer?
So is it like std::unique_ptr, i.e. when it goes out of scope, it gets deallocated?
Francesco Biscani
@bluescarni
Jul 19 2015 19:53
yep.. yes the destroyer of the box cleans up eveything
Ondřej Čertík
@certik
Jul 19 2015 19:53
If you copy the box, it just copies the object by value?
Francesco Biscani
@bluescarni
Jul 19 2015 19:54
yes
Ondřej Čertík
@certik
Jul 19 2015 19:54
how to do you construct it though --- does it get allocated on the heap?
Francesco Biscani
@bluescarni
Jul 19 2015 19:54
the box internally contains a pointer to allocated space yes
Ondřej Čertík
@certik
Jul 19 2015 19:55
Ok, so it is just like std::unique_ptr, but it copies it by value instead.
while std::unique_ptr needs to be moved, I don't think you can copy it.
Francesco Biscani
@bluescarni
Jul 19 2015 19:56
yes exactly
Ondřej Čertík
@certik
Jul 19 2015 19:56
You might be interested in this: certik/trilinos#2
It's a Viewable class, that stores the object on stack, but allows you to get a Debug time checked Ptr out of it and pass it around.
In Release mode, it is as fast as a stack allocated object. No pointers.
I.e. in Release mode, there is no overhead of Viewable, but in Debug mode you can pass safe pointers to it around.
Francesco Biscani
@bluescarni
Jul 19 2015 19:59
that's pretty interesting.. is it similar to the observer pointer?
Ondřej Čertík
@certik
Jul 19 2015 20:00
You can get observer pointer (Ptr) out of it.
The observer pointer is not safe on its own.

Essentially it's about this:

+  int *ip;
+  {
+    int i = 1;
+    i += 10;
+    ip = &i;
+    TEST_EQUALITY(*ip, 11);
+  }
+  // *ip is now dangling

vs this:

+  Ptr<int> ip;
+  {
+    Viewable<int> i = 1;
+    *i += 10;
+    ip = i.ptr();
+    TEST_EQUALITY(*ip, 11);
+  }
+#ifdef TEUCHOS_DEBUG
+  TEST_THROW( *ip, DanglingReferenceError );
+#endif
Both codes are 100% equivalent in Release mode, but in Debug mode the first will segfault (in a better case...), while the second will give you a nice exception.
Francesco Biscani
@bluescarni
Jul 19 2015 20:02
ok I see, that's pretty neat
Ondřej Čertík
@certik
Jul 19 2015 20:02
(In Release mode, there is no heap allocation, it's all on stack.)
Francesco Biscani
@bluescarni
Jul 19 2015 20:04
due to the way Piranha works, I very rarely have to deal with pointers... I can't actually remember if I ever head a situation in which there was a dangling pointer
but I can see it being very useful in OO programming
Ondřej Čertík
@certik
Jul 19 2015 20:05
Do you know how to design SymEngine, so that I don't have to use pointers? Essentially I would need to do everything by value. I should try it out.
I can still pass pointers around with things like Viewable and Ptr, which is safe, but I wouldn't need to use heap allocation at all.
Francesco Biscani
@bluescarni
Jul 19 2015 20:05
so the thing I would look into for that would be definitely type erasure
Ondřej Čertík
@certik
Jul 19 2015 20:06
Well, I would need to use heap allocation for value types, not for pointers.
Ok, I am studying the presentation now.
Francesco Biscani
@bluescarni
Jul 19 2015 20:06
but it requires some more research as it is not well-explored territory as classic OO
the other day I was thinking how you would possibly serialise a type-erased type
I have a couple of ideas about it now, but it's the type of problems that need to be solved
Ondřej Čertík
@certik
Jul 19 2015 20:07
I know. For a CAS, there are previous implementations that use similar design as SymEngine, so that's why I chose to do it that way, as it is known it would work and be reasonably fast. But I am still exploring these alternative approaches.