what is the point of sexp_of_opaque? - ocaml

In ppxlib it says that
sexp_of_opaque x converts the value x of opaque type to an S-expression. This means the user need not provide converters, but the result cannot be interpreted.
Does it mean I can call this on any types? But what is the point if I cannot do anything with it?

The converter sexp_of_opaque matches any value of any type to <opaque>.
It can be useful to represent holes in the sexp representation or when using the base or core library to have a placeholder function for sexp conversion when such function is expected in a functor argument.

Related

What's the difference between C++23's optional::transform and optional::and_then?

C++23 adds some "monadic-style" functionality regarding optionals, as methods of optional<T>:
optional<T>::and_then() (and ignoring qualifiers of this):
template<class F> constexpr auto and_then(F&& f);
Returns
the result of invocation of f on the contained value if it exists.
Otherwise, returns an empty value of the return type.
optional<T>::transform() (and ignoring qualifiers of this):
template<class F> constexpr auto transform(F&& f);
Returns an std::optional that contains the result of invocation of f on the contained value if *this contains a value. Otherwise, returns an empty std::optional of such type.
So, aren't these two functions doing the same thing?
Suppose you have an optional<T1> value.
transform() lets you pass your optional to functions like T2 foo(T1 x);
and_then() lets you pass your optional to functions like optional<T2> bar(T1 x);
... and get an optional<T2> at the end. So, transform() will "re-box" the function's output into an optional, while and_then() will expect the function to return a boxed value on its own.
See also this question.
and_then is monadic bind aka flatmap aka >>= and transform is functorial map.
One can express map in terms of bind generically, but not the other way around, because a functor is not necessarily a monad. Of course the particular monad of std::optional can be opened at any time, so both functions are expressible in terms of ordinary pre-C++23 std::optional API. Thus the question why the C++ standard defines both functions is no better than the question why it defines any of the two. Perhaps the Standard wishes to give the programmer a standard functorial interface and a standard monadic interface independently. Either interface is useful and important on its own right.
and_then only takes functions of type T -> std::optional<U> (whereas transform is free to take functions returning any type).
If you just transform with such a function you will get a std::optional<std::optional<U>>.
and_then just then flattens the std::optional<std::optional<U>> into an std::optional<U>.
That's all monads are: transform composed with a type level flatten. Think range<range<U>> and future<future<U>>.

Placeholder variable type

I need to get information from a class function. Said class has overloaded operators for basically any standard type. Therefore
double foo = exampleObject.getInformation();
and
std::string faa = exampleObject.getInformation();
Would both work. If the information can not be transformed into a double, foo will be set to 0. The initialization of faa will always work. (It can always be expressed as a string)
My problem is: I want to get the information and save it as a double variable, if that can not be done as the information is not of numeric type, I want the variable to be a string. I basically need a variable that can change its type. How do I do this? I'm sorry if that is a very basic question, C++ is not my main programming language.
Have you tried using Function Templates?
They won't change the type of a variable but will allow you to write your code in a way that works with more than 1 data type.
If c++ is not your main, I would recommend checking the checking the documentation for Function Templates on cplusplus.com
Here => https://cplusplus.com/doc/oldtutorial/templates/

Is it possible to dynamically create and store pointers for functions for which we don't know the number and type of arguments?

I've been given a bunch of dummy functions, each one with its own return type, number (and types) of arguments and I'm trying to figure out a way to create function pointers of the correct type to them automatically, then store them inside a map to be retrieved at will. In a nutshell, I'm stuck at creating the actual function pointers. The way of storing them in a map is a separate, follow-up question, due to their variable types.
I think that templates are the way to go, and I've tried creating a templated function that returns the appropriately-typed pointer given the address and types of a function. I think it could not be possible though, so any input is appreciated.
Code for the aforementioned function:
template <typename retType, typename ... argTypes> retType makeFuncPtr(void* funcAddr) {
retType (*ptr)(argTypes) = funcAddr;
return ptr;
}
I'm getting an error "Declaration type contains unexpanded parameter pack 'argTypes'". What am I doing wrong and also which is the appropriate return type for this function, as I'm not actually sure about it?
The error you ask about is because in the line:
retType (*ptr)(argTypes) = funcAddr;
there is no ... after argTypes. Note this would not actually fix the situation because a void pointer can not be converted to some other kind of pointer without a cast. And also you could not convert the function pointer to retType.
If the functions have different signatures this is a fairly tricky problem, I suggest you take a look at libffi, the tricky part here is not storing the function pointers (so long as they are not non-static member functions you can simply cast to void * and store that), the tricky part is using the stored pointer value to make a call.
libffi gives you the ability to describe a function's calling convention, return type and expected arguments. You could then write code that compares the arguments you actually received and either convert or produce an error as appropriate. With C++ it would even be possible to produce that description programmatically (your template function would take a function pointer as a parameter then use the parameter pack to map to the libffi argument type values).

Passing java.lang.Long to Integer constructor

(Integer. 1)
As I understand it is the same as following Java code:
new Integer(1)
So now I have got following construction
(Integer. (Long. 1))
#=> 1
How does this work? Java Integer class has got two constructors and they don't accept Long.
By the way, following doesn't work:
(Long. (Integer. 1))
This indeed seems like a bug in Clojure. For Java, it's the other way around. This seems related to CLJ-445, an "enhancement" request that is over five years old. It's perhaps best to ping that issue with this trivial example.
new Long(new Integer(1)) should be acceptable due to a combination of unboxing and widening.
With unboxing (the inverse of autoboxing), some objects are implicitly converted to primitive types:
Converting an object of a wrapper type (Integer) to its corresponding primitive (int) value is called unboxing. The Java compiler applies unboxing when an object of a wrapper class is:
Passed as a parameter to a method that expects a value of the corresponding primitive type.
Assigned to a variable of the corresponding primitive type.
In this example, Integer objects are implicitly reduced to int, and Long objects are implicitly reduced to long.
With widening, primitive types can be implicitly converted to "wider" primitive types when this is possible without information loss. This means that an int can be converted to a long, but not the other way around, so new Integer(new Long(1)) should be rejected.

Widening of integral types?

Imagine you have this function:
void foo(long l) { /* do something with l */}
Now you call it like so at the call site:
foo(65); // here 65 is of type int
Why, (technically) when you specify in the declaration of your function that you are expecting a long and you pass just a number without the L suffix, is it being treated as an int?
Now, I know it is because the C++ Standard says so, however, what is the technical reason that this 65 isn't just promoted to being of type long and so save us the silly error of forgetting L suffix to make it a long explicitly?
I have found this in the C++ Standard:
4.7 Integral conversions [conv.integral]
5 The conversions allowed as integral promotions are excluded from the set of integral conversions.
That a narrowing conversion isn't being done implicitly, I can think with, but here the destination type is obviously wider than the source type.
EDIT
This question is based on a question I saw earlier, which had funny behavior when you didn't specify the L suffix. Example, but perhaps it's a C thing, more than C++?!!
In C++ objects and values have a type, that is independent on how you use them. Then when you use them, if you need a different type it will be converted appropriately.
The problem in the linked question is that varargs is not type-safe. It assumes that you pass in the correct types and that you decode them for what they are. While processing the caller, the compiler does not know how the callee is going to decode each one of the arguments so it cannot possibly convert them for you. Effectively, varargs is as typesafe as converting to a void* and converting back to a different type, if you get it right you get what you pushed in, if you get it wrong you get trash.
Also note that in this particular case, with inlining the compiler has enough information, but this is just a small case of a general family if errors. Consider the printf family of functions, depending on the contents of the first argument each one of the arguments is processed as a different type. Trying to fix this case at the language level would lead to inconsistencies, where in some cases the compiler does the right thing or the wrong one and it would not be clear to the user when to expect which, including the fact that it could do the right thing today, and the wrong one tomorrow if during refactoring the function definition is moved and not available for inlining, or if the logic of the function changes and the argument is processed as one type or another based on some previous parameter.
The function in this instance does receive a long, not an int. The compiler automatically converts any argument to the required parameter type if it's possible without losing any information (as here). That's one of the main reasons function prototypes are important.
It's essentially the same as with an expression like (1L + 1) - because the integer 1 is not the right type, it's implicitly converted to a long to perform the calculation, and the result is a long.
If you pass 65L in this function call, no type conversion is necessary, but there's no practical difference - 65L is used either way.
Although not C++, this is the relevant part of the C99 standard, which also explains the var args note:
If the expression that denotes the called function has a type that
does include a prototype, the arguments are implicitly converted, as
if by assignment, to the types of the corresponding parameters, taking
the type of each parameter to be the unqualified version of its
declared type. The ellipsis notation in a function prototype
declarator causes argument type conversion to stop after the last
declared parameter. The default argument promotions are performed on
trailing arguments.
Why, (technically) when you specify in the declaration of your function that you are expecting a long and you pass just a number without the L suffix, is it being treated as an int?
Because the type of a literal is specified only by the form of the literal, not the context in which it is used. For an integer, that is int unless the value is too large for that type, or a suffix is used to specify another type.
Now, I know it is because the C++ Standard says so, however, what is the technical reason that this 65 isn't just promoted to being of type long and so save us the silly error of forgetting L suffix to make it a long explicitly?
The value should be promoted to long whether or not you specify that type explicitly, since the function is declared to take an argument of type long. If that's not happening, perhaps you could give an example of code that fails, and describe how it fails?
UPDATE: the example you give passes the literal to a function taking untyped ellipsis (...) arguments, not a typed long argument. In that case, the function caller has no idea what type is expected, and only the default argument promotions are applied. Specifically, a value of type int remains an int when passed through ellipsis arguments.
The C standard states:
"The type of an integer constant is the first of the corresponding list in which its value can be represented."
In C89, this list is:
int, long int, unsigned long int
C99 extends that list to include:
long long int, unsigned long long int
As such, when you code is compiled, the literal 65 fits in an int type, and so it's type is accordingly int. The int is then promoted to long when the function is called.
If, for instance, sizeof(int) == 2, and your literal is something like 64000, the type of the value will be a long (assuming sizeof(long) > sizeof(int)).
The suffixes are used to overwrite the default behavior and force the specified literal value to be of a certain type. This can be particularly useful when the integer promotion would be expensive (e.g. as part of an equation in a tight loop).
We have to have a standard meaning for types because for lower level applications, the type REALLY matters, especially for integral types. Low level operators (such as bitshift, add, ect) rely on the type of the input to determine overflow locations. ((65 << 2) with integers is 260 (0x104), but with a single char it is 4! (0x004)). Sometimes you want this behavior, sometimes you don't. As a programmer, you just need to be able to always know what the compiler is going to do. Thus the design decision was made to make the human explicitly declare the integral types of their constants, with "undecorated" as the most commonly used type, integer.
The compiler does automatically "cast" your constant expressions at compile time, such that the effective value passed to the function is long, but up until the cast it is considered an int for this reason.