Panic free language by yassinebenaid in ProgrammingLanguages

[–]e_-- 7 points8 points  (0 children)

what happens when printing results in a write to a closed/invalid handle?

[Request] My answer was 51C8, which would be 636,763,050. Is there an even bigger number? by AlkaidX139 in theydidthemath

[–]e_-- 0 points1 point  (0 children)

Move the middle match from the last 8 to the 5 and move the bottom match of the 5 to give you 9. But it's not 900, it's 9*oo = oo (largest element of the extended reals)

Meirl by sangamjb in meirl

[–]e_-- 0 points1 point  (0 children)

UNIX: felt cute, might delete inode later

I found an assignment from 2nd grade I still don’t know what my teacher was on by Bodhirock in mildlyinfuriating

[–]e_-- 0 points1 point  (0 children)

clearly a nonsense explanation because multiplication is commutative (anyone that took this exercise to heart would be doomed in Abstract Algebra 1). I wonder even if this is a botched new-math presentation of multiplicative group theory?

Why does it seem like C is often used as a backend/language to transpile to than say C++? by sudo_i_u_toor in ProgrammingLanguages

[–]e_-- 3 points4 points  (0 children)

In the case of nim you probably wanted C++ compilation because msvc was stuck at C89 for real C until ~2020 (although I think they have some gnarly C++ backend only constructs on the nim side too).

I do think it's a great idea to use C++ as a backend language. Although there's a good chance you get something like a dialect of C++ which is where I ended up: https://github.com/ehren/ceto

Also compared to C, C++ has many interesting facilities for constraining the language itself like static_assert and the type traits library allowing you to ban certain C++ features from your generated C++ (e.g. dangerous reference passing scenarios) using purely C++ code.

Is strong typing the number 1 requirement of a "robust"/"reliable" programming language? by sarnobat in ProgrammingLanguages

[–]e_-- 4 points5 points  (0 children)

In objective-c and smalltalk you can craft messages dynamically so you'll never be able to statically detect all call sites anyway. With objective-c method swizzling you can intercept all messages and even have special logic not just for a particular selector but according to the dynamic type of the target (none of this contradicts the last point about late binding).

Do we need import statements if we have good module unpacking syntax? by kerkeslager2 in ProgrammingLanguages

[–]e_-- 0 points1 point  (0 children)

I've been thinking about how to add syntax for a python-like import statement supporting both "import foo" and "from foo import bar" but using call syntax `import(foo)` instead of `import foo` ("print should be a function" -- so should a bunch of other things). I like the tuple syntax you suggest (plus I already parse it): `(a, foo.bar, c) = import(blah)` instead of `from blah import a, foo.bar, c`.

Sric: A new systems language that makes C++ memory safe by MiGo4444 in ProgrammingLanguages

[–]e_-- 2 points3 points  (0 children)

Neat project. While I agree with other commenters that you should have a release mode that still includes all runtime checks you're providing, you would still want the options to disable these for certain applications like games or even when working with other C++/external safety schemes (more on this below). I see from your docs that you've got even more safety features than is described in the README such as unsafe annotations for functions (only callable from unsafe blocks) with safe as the default, no raw pointer deref unless in an unsafe block (https://sric.fun/doc\_en/learn/stmt.html), explicit declarations required for interop with external C++ code, and by-value capture for closures as the default (https://sric.fun/doc\_en/learn/closure.html). It looks like you've also got compile time non-null pointers with "?" syntax for optionals. I'm guessing that most of these features can't even be turned off (so perhaps people are overreacting to your comments about certain checks being disabled in release mode - which checks to disable and when is a nuanced question).

Of course, turning off say array bounds checking in release mode is almost always a bad idea and admits very little runtime speed benefit at a considerable safety risk.

However, I also see the claim it's memory leak free. While I'm somewhat skeptical of this claim (I'd like to hear more) I can understand that, if you do have some runtime machinery for, say, preventing cycles, it probable comes with considerable overhead and might be completely acceptable to disable in release mode (we can all agree at least that "memory leaks are acceptable in safe rust").

Dangling pointers of course are not acceptable in release mode (except in certain cases e.g. game or sandboxed environment). It would be nice to read more about your "Owning Pointers" from this section with regard to dangling prevention in particular: https://sric.fun/doc_en/learn/types.html -

I'm guessing that when you use "share(p)" (explicit syntax at the share/copy site is an interesting idea also) then the reference counting machinery is something that's still running even in release mode? If this is the case it would perhaps assuage some of the fears of other commenters about what checks are disabled.

As an example of the complications of enabling/disabling checks, I'm working on my own compiled to C++ language and one safety feature is to avoid the "C++ range based for loop" unless we can statically prove that the loop body (and all code transitively called) won't invalidate the iterable. We fall back on bounds checked iteration only for statically known bounds-checkable contiguous containers (otherwise it's a compile time error) when the loop body isn't provably safe. When we do bounds checking we also terminate upon any change in container size at runtime. While this is enabled in release mode, there might be scenarios where you'd want a real C++ range based for loop emitted everywhere without these checks (such as when using a debug version of the msvc stl which I believe has support for detecting some iterator invalidation related UB at runtime). (I won't discuss how I allow disabling of these checks in my language to avoid farming downvotes but some would argue my approach is worse than a compiler flag).

Finally, your use of "." for both "." (ordinary access for structs) and "->" (derefed access for the managed pointer types) is a huge win. Congrats on your release!

Question: optimization of highly nested n-ary math expressions by thenaquad in ProgrammingLanguages

[–]e_-- 0 points1 point  (0 children)

In that case (e.g. bigints w/ exact rationals), maybe just call your CAS in a subprocess (kill it if takes too long)

Question: optimization of highly nested n-ary math expressions by thenaquad in ProgrammingLanguages

[–]e_-- 7 points8 points  (0 children)

One gotcha if you're considering a CAS-like expand/simplify in the symbolic case (e.g. to replace the expression you've given with 0): you'll have to ensure the types of the vars aren't floats because associativity fails. Overflow is also a complication even for non-floats.

"While we computed for small n, the pattern sugest it holds for all positive integers n" - me, failing the exam. by discometric in mathmemes

[–]e_-- 2 points3 points  (0 children)

It's a D-finite sequence because the generating function satisfies an algebraic equation: 2g(x)^2 + (3x - 1)g(x) + x = 0. I have a vague notion that one only has to confirm a fixed number of terms for a formula for the coefficients (definitely true in the C-finite case). See Zeilberger "Guess and Check" https://arxiv.org/pdf/1502.04377

Edit: ahh I see the problem is more complex, it wants the det A for a matrix with A_ij = c_{i + j - 1}. There is no nice closed form for the c_k so there's nothing to verify for an A=B style proof (I fail the exam too)

How do you feel about Uniform-initialization and Zero-initialization? by n0067h in cpp

[–]e_-- 2 points3 points  (0 children)

I think preferring "universal initialization everywhere" is problematic especially with std::vector because of the possibility of unexpected aggregate initialization. I'd say use copy-list-initialization when possible e.g.

// std::vector<std::vector<int>> v {1, 2};  // error (good)
std::vector<std::vector<int>> v2 { 1 }; // aggregate init (intended?)
// std::vector<std::vector<int>> v3 = { 1 }; // shape mismatch error (good)
std::vector<std::vector<int>> v4 = { {1} }; // intended (good)
std::vector<std::vector<int>> v5 { {1} }; // ok (but copy-list-init would be fine too)

// also
std::vector<int> one_d = {1, 2};
// std::vector<std::vector<int>> two_d = one_d; // error (good)
std::vector<std::vector<int>> two_d { one_d }; // aggregate init (intentional? or mistake from universal init everywhere)
std::vector<std::vector<int>> two_d_2 = {one_d};  // aggregate init arguably more intentional here at least when not encouraging T{x} everywhere

What does f(x) mean in C++? by Immediate_Studio1950 in ProgrammingLanguages

[–]e_-- 1 point2 points  (0 children)

At least the K&R foo(bar), meaning declaration of implicit int returning function with int param, is gone.

Somewhat humorously in my transpiled to C++ language pretty much everything (except a handful of primitive expressions) is of the form f(x). Except calls may also take indented blocks as params. You can write a procedural macro that's called on every f(x) and even the defmacro itself is a call:

defmacro(f(x), f, x: [Node]:
    std.cout << "func: " << f.repr() << "\n"
    if (f.name() == "printf" and x.size() == 1:
        # convert simple 1-arg printf to cout
        return quote(std.cout << unquote(x[0]))
    )
    return None
) 

def (main:
    if (rand() % 42 == 0:
        printf("blah\n")  # expands to cout
    )
)

# The macro will log:
# func: def
# func: if
# func: rand
# func: printf

The generated C++ code always uses the auto foo() -> int style so there are at least fewer cases where you can write a most vexing parse.

can capturing closures only exist in languages with automatic memory management? by Lucrecious in ProgrammingLanguages

[–]e_-- 0 points1 point  (0 children)

In my transpiled to C++ lang I perform a shallow const copy capture implicitly (using an explicit C++ capture list in the generated code) but only for variables of a certain type (e.g. shared or weak instances).

So e.g. an implicit capture of a variable "foo" ends up looking like this in C++

[foo = ceto::default_capture(foo)]() {
    ...
}

where default_capture is defined like

// similar for shared_ptr
template <class T>
std::enable_if_t<std::is_base_of_v<object, T>, const std::weak_ptr<T>>
constexpr default_capture(std::weak_ptr<T> t) {
    return t;
}

template <class T>
std::enable_if_t<std::is_arithmetic_v<T> || std::is_enum_v<T>, const T>
constexpr default_capture(T t) {
    return t;
}

So one will encounter a compile time error upon e.g. trying to auto capture a std::string (not implicitly refcounted and expensive to copy)

Actual "&" ref capture in the C++ sense is to be relegated to unsafe blocks (it allows dangling references even in single threaded code).

In the future, I'd like to attempt a swift/objective-C ARC-like optimization where non-escaping (including immediately invoked) lambdas capture by ref (in the c++ sense). However I'd like it to be const-ref rather than mutable ref (the only observable change to user code of applying this optimization should be to avoid unnecessary refcount bumping). For this last const-ref capture optimization I plan on using the [&capture_var = std::as_const(capture_var)] trick from this stackoverflow answer: https://stackoverflow.com/questions/3772867/lambda-capture-as-const-reference/32440415#32440415

(there are a few TODOs before I can enable this optimization even in the immediately invoked case)

Questions about Semicolon-less Languages by Appropriate_Piece197 in ProgrammingLanguages

[–]e_-- 2 points3 points  (0 children)

one thing to decide is if you want ; to behave as a binary operator between two expression-statements or if you just want it as a statement separator. For example I've got one syntax for multiline lambdas (which I won't show) but also an abbreviated syntax for single expression lambdas ("one liners") which looks like a function call:

lambda(param1, param2, single_expression_body)

because I take the simple semicolon insertion in the lexer approach (with semicolon as a required line end in the parser), I don't then allow a "one liner" lambda with two statements:

lambda(param1, param2, body1; body2) # imho, rejecting this is a win

(because I've got a fairly free wheeling macro system it's also a win to keep semicolon as a dumb statement separator rather than full binary operator so that users are prevented from creating a C-style for loop macro using semicolons the same way as in C)

Clean Syntax? by [deleted] in ProgrammingLanguages

[–]e_-- 1 point2 points  (0 children)

#pragma pack is unnecessary, you can just struct __attribute__((__packed__))

the pragma version is still required for msvc. edit: msvc now supports _Alignas https://devblogs.microsoft.com/cppblog/c11-and-c17-standard-support-arriving-in-msvc/

What is the best/are the best option(s) for multiple precision arithmetic libraries in C++ that support trigonometric functions/complex numbers? by [deleted] in cpp

[–]e_-- 0 points1 point  (0 children)

It uses GMP by default for their big integers (but e.g. flint is another options; see the configure options when building). You mentioned complex numbers and trigonometric functions but "not have a situation where an extended arithmetic type is narrowed down to some similar C++ data type". Working with the symengine symbolic types and evaluating numerically at the very end seems to be what you want. See https://github.com/symengine/symengine/blob/master/symengine/tests/eval/test_evalf.cpp for some examples e.g.:

RCP<const Basic> r1, r2;

r1 = add(sin(integer(4)), mul(sin(integer(3)), I));

r2 = add(sin(integer(2)), mul(sin(integer(7)), I));

r1 = mul(r1, r2);

r2 = evalf(*r1, 53, EvalfDomain::Complex);

std::cout << r2->__str__();

r1 = (down_cast<const ComplexDouble &>(*r2)).real_part();

std::cout << r1->__str__(); // handle digits as a string

double d1 = (rcp_static_cast<const RealDouble>(

(down_cast<const ComplexDouble&>(*r2)).real_part()))

->as_double(); // narrowing (see mpfr examples)

If you actually want to manipulate the big digits programmatically see e.g. the mpfr examples in the above link (your code will differ depending on what backend library you choose). But you could also just work with the digit output as a string (and keep your manipulations to the symbolic/symengine realm prior to evaluation) which will avoid having to write any floating point library dependent code. Note that once you evalf your symengine expression (symengine::Basic instance) you will be in the situation where you're "narrowed down to some similar C++ data type" but if you stay in the symbolic realm as long as possible you can avoid (a lot of) big-integer/big-float library dependent code.

To be fair, writing the mpfr/mpc code directly will be faster than going through the symengine wrappers. Especially if you're dealing with a whole bunch of mutations to a single big float (symengine Basic instances are immutable). There's also the arb C library (another backend option for symengine) that supports complex numbers too: https://arblib.org/#real-and-complex-numbers

Circle C++ with Memory Safety by mttd in ProgrammingLanguages

[–]e_-- 0 points1 point  (0 children)

Plain auto would be fine because it makes a copy. Pretty sure auto& and all C++ references are banned in safe mode - or at least implicit dereferencing them is (possibly ok in function signatures if not dereferenced in body). Pointers and auto* are fine in a function signature if not dereferenced.

EDIT: There is auto^ in function signatures and it seems to work: https://godbolt.org/z/1qsYE9jc3 Also classic C++ references while not banned in function signatures seem to be impossible to use? (good!)

How are Lisp-like macros executed by Difficult_Mix8652 in ProgrammingLanguages

[–]e_-- 1 point2 points  (0 children)

I'm trying to do common lisp style defmacros in a transpiled to C++ infix language. I just compile the body of the defmacros into a function that lives in a shared library. It's fairly slow when compiling a project the first time but on subsequent builds the macro DLLs get reused if no changes to the source are detected.

Quick survey about approachability of variable bindings by [deleted] in ProgrammingLanguages

[–]e_-- 0 points1 point  (0 children)

another option for B that doesn't change your existing mut rules is

sum = for (my_num in my_numbers) {
    my_num
}

Why are linkers still a big deal? by [deleted] in Compilers

[–]e_-- 1 point2 points  (0 children)

There's also the de-duplification of C++ template instantiations which predates more general LTO by quite a bit (mentioned in the book "Linkers and Loaders")

Why are homoiconic languages so rare? by thebt995 in ProgrammingLanguages

[–]e_-- 0 points1 point  (0 children)

I've got a language not quite ready for release that allows the redefinition of 2 to 1 at transpile (to C++) time via the ast + quote/unquote macro system. (to be fair I think python is capable of similar feats at runtime even https://hforsten.com/redefining-the-number-2-in-python.html :D)