Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A baffling bug in my bignumber code (expressive C++ dialect)

155 views
Skip to first unread message

Alf P. Steinbach

unread,
Feb 22, 2017, 11:36:27 PM2/22/17
to
I decided to do a little challenge we used to give to the students in
Bodø in the mid 1990s: to implement a bignumber class and use it to
compute the Fibonacci sequence up to a ridiculous length.

Checking my results against a Python script to do the same (Python has a
built-in bignumber type that's used automatically) I found that
Fib[121], while correctly computed as bignum bits, was displayed
incorrectly as decimal. Strange. So I added checking of the last digit:

#include <p/expressive/using_weakly_all.hpp>

#include <p/cppx/value_types/Big_int.hpp>
$using_nested_namespace( progrock, cppx );

#include <iostream>
$using_weakly_all_from_ns( std );

$procedure show_fibonacci()
{
using cppx::Big_int;

$let_mutable a = Big_int{ 1 };
$let_mutable b = Big_int{ 0 };
$let_mutable last_digit_of_a = 1;
$let_mutable last_digit_of_b = 0;

for( $each i $in i_up_to( 123 ) )
{
$let next = a + b;
$let s = next.to_decimal();
$let last_digit_of_next = s.back() - '0';
cout << i << " - " << s << " or in hex: " << next.to_hex()
<< endl;
$hopefully( last_digit_of_next == (last_digit_of_a +
last_digit_of_b) % 10 )
or $fail( "Ooops, that last result had incorrect last
decimal digit..." );
a = b; b = next;
last_digit_of_a = last_digit_of_b; last_digit_of_b =
last_digit_of_next;
}
}

$just{ show_fibonacci(); }

The last few lines of the output when I run it:

114 - 483162952612010163284885 or in hex: 665050EED5966FB5AB95
115 - 781774079430987230203437 or in hex: A58C0EC9B9E4287BCE2D
116 - 1264937032042997393488322 or in hex: 10BDC5FB88F7A983179C2
117 - 2046711111473984623691759 or in hex: 1B1686E82495EC0AD47EF
118 - 3311648143516982017180081 or in hex: 2BD44CE3AD8D958DEC1B1
119 - 5358359254990966640871840 or in hex: 46EAD3CBD2238198C09A0
120 - 8670007398507948658051921 or in hex: 72BF20AF7FB11726ACB51
121 - 14028385100242989008475377 or in hex: B9A9F47B51D498BF6D4F1

! show_fibonacci - Ooops, that last result had incorrect last
decimal digit...

Internally the number, at this point where things go wrong, has 3 32-bit
digits, and when the decimal presentation is /translated back/ to hex
it's correct except for the least significant hex digit of the most
significant 32-bit digit, which hex digit is 2 too large...

The to-decimal function is inefficient because it's just a way to get
decimals without using division, because I've not implemented division:

inline $function Big_int::to_decimal() const
-> string
{
$using_from_namespace( expressive, operator<< );
if( is_zero() ) { return "0"; }
else if( is_negative() ) { return "-"s <<
(-$self).to_decimal(); }
else
{
$let_mutable remaining = $self;
$let_mutable exponent = $lambda_using_references() -> int
{
$let_mutable power_of_ten = Big_int{1};
$let_mutable exp = 0;
while( power_of_ten <= remaining )
{
power_of_ten *= 10;
++exp;
}
return exp - 1;
}();

$let_mutable result = ""s;
while( exponent >= 0 )
{
$let power_of_ten = pow( Big_int{10}, exponent );
$let_mutable decimal_digit = 0;
while( decimal_digit*power_of_ten <= remaining )
{
++decimal_digit;
}
--decimal_digit;
result << char( '0' + decimal_digit );
$let k = remaining;
remaining -= decimal_digit*power_of_ten;
assert( remaining + decimal_digit*power_of_ten == k );
--exponent;
}
assert( remaining.is_zero() );
return result;
}
}

I can't see anything wrong, and (1) everything works just fine for the
first 121 Fibonacci numbers, and (2) the asserts don't trigger.

I'm baffled by my own bug.

Which is possibly in the subtraction operator or something, but I'm
exhausted & hungry; I'll eat and watch a movie, and see tomorrow if
anyone saw something blindingly obviously wrong?


Cheers!

- Alf

Ben Bacarisse

unread,
Feb 23, 2017, 9:42:26 AM2/23/17
to
Not sure what all the $stuff is, but

fib(121) = 14028366653498915298923761

which differ from you decimal value of 14028385100242989008475377 by
18446744073709551616 which is 2^64. I.e. it's not just the last digit
(the hex value is correct).

> Internally the number, at this point where things go wrong, has 3
> 32-bit digits, and when the decimal presentation is /translated back/
> to hex it's correct except for the least significant hex digit of the
> most significant 32-bit digit, which hex digit is 2 too large...

I didn't follow this.
Maybe there is some carry propagation error where the addition in the
assert cancels the error from the subtraction. Do you subtract by
adding and fiddling the signs?

<snip>
--
Ben.

Mr Flibble

unread,
Feb 23, 2017, 12:57:17 PM2/23/17
to
All this $let_mutable and such bollocks makes your code harder to grok
than standard C++ so I have no interest in examining it and therefore
answering your questions about it.

/Flibble

Alf P. Steinbach

unread,
Feb 23, 2017, 3:23:54 PM2/23/17
to
On 23.02.2017 18:57, Mr Flibble wrote:
>
> All this $let_mutable and such bollocks makes your code harder to grok
> than standard C++ so I have no interest in examining it and therefore
> answering your questions about it.

Thanks, I think you're right about `$let_mutable`: it's too verbose by far.

The `$let` pseudo-keyword is shorter than the `auto const` that it
translates to, but `$let_mutable` is much longer than `auto`, just to
sort of press it into the same conceptual fold. It's idealism. Ungood.

I'm changing it to just `$var`, which is the conventional keyword for a
variable in JavaScript and C#.

#include <p/expressive/using_weakly_all.hpp>

#include <p/cppx/value_types/Big_int.hpp>
$using_nested_namespace( progrock, cppx );

#include <iostream>
$using_weakly_all_from_ns( std );

$procedure show_fibonacci()
{
using cppx::Big_int;

$var a = Big_int{ 1 };
$var b = Big_int{ 0 };
$var last_digit_of_a = 1;
$var last_digit_of_b = 0;

for( $each i $in i_up_to( 123 ) )
{
$let next = a + b;
$let s = next.to_decimal();
$let last_digit_of_next = s.back() - '0';

cout << i << " - " << s << " or in hex: " << next.to_hex()
<< endl;
$hopefully( last_digit_of_next == (last_digit_of_a +
last_digit_of_b) % 10 )
or $fail( "Ooops, that last result had incorrect last
decimal digit..." );
a = b; b = next;
last_digit_of_a = last_digit_of_b; last_digit_of_b =
last_digit_of_next;
}
}

$just{ show_fibonacci(); }

Cheers!, & thanks,

- Alf

Alf P. Steinbach

unread,
Feb 23, 2017, 3:40:01 PM2/23/17
to
Thank you that clarified things for me.


>> [snip]
>> I can't see anything wrong, and (1) everything works just fine for the
>> first 121 Fibonacci numbers, and (2) the asserts don't trigger.
>
> Maybe there is some carry propagation error where the addition in the
> assert cancels the error from the subtraction.

Yes, that sounds very likely.


> Do you subtract by adding and fiddling the signs?

Yes. I was lazy, didn't want to deal with carry.

inline $procedure Big_int::operator-=( ref_<const Big_int> other )
{
if( is_positive() != other.is_positive() )
{
$self += -other;
return;
}

$let n_digits_this = n_items_in( digits_ );
$let n_digits_other = n_items_in( other.digits_ );
$let n_operand_digits = max( n_digits_this, n_digits_other );

digits_.reserve( n_operand_digits + 1 );

// The following performs subtraction of the magnitudes. If
this produces
// a negative magnitude, then the original sign is flipped.

// Add ((a big power of R) - other), where R, the radix of the
numeral
// system used for digits_, is the number of possible digit values.
$let big_minus_one_minus_other = other.complemented_wrt(
n_operand_digits );
add( big_minus_one_minus_other, 1 );

// Subtract the big power of R that was added.
if( n_items_in( digits_ ) > n_operand_digits )
{
// The magnitude result is positive or 0.
assert( digits_.back() == 1 );
digits_.resize( n_operand_digits );
}
else
{
// The magnitude result is negative, but is brought to
positive by the
// big power of R.

// Compute (big - this), pretending to be positive for the
increment:
$let real_sign = exchange( is_negative_, false );
complement_wrt( n_operand_digits );
add( 1 );
// And then compute (this - big) =
is_negative_ = not real_sign;
}
remove_leading_zeroes();
}

The bignum state is a vector `digits_` and a boolean `is_negative_`, and
the representation is sign-and-magnitude, with zero as an empty vector
and `is_negative_` set to `false`.

`exchange` here is `std::exchange`. I learned about it just some months
back, so I feel that not every reader would be familiar with it.

I feel sure that your informed hunch is in the right direction, and it
should have nailed it down, but I still don't see where I go wrong...


Cheers!, and thanks,

- ALf

leigh.v....@googlemail.com

unread,
Feb 23, 2017, 4:26:57 PM2/23/17
to
$var instead of auto? Why don't you like the auto keyword? Why do you prefer obfuscation to idiomatic C++? What you are doing try to make C++ code look like code from other inferior languages is really egregious.

Alf P. Steinbach

unread,
Feb 23, 2017, 6:42:50 PM2/23/17
to
On 23.02.2017 22:26, leigh.v....@googlemail.com wrote:
> $var instead of auto? Why don't you like the auto keyword?

I don't /dislike/ `auto`. But `auto` has many different meanings, and
that makes it

• hard to search for e.g. variable declarations as opposed to constant
or reference declarations,

• hard to see at a glance what kind of declaration (such as variable or
constant, as in the array example below) a declaration is,

• hard to see what type a declaration is about, and

• I believe, difficult to learn to use correctly for a novice.

These are problems that are somewhat alleviated by the $ pseudo-keywords.

There are also problems, some mentioned below, that are irrelevant for
the use or not of pseudo-keywords, at least as long as they're macros
and not more real keywords supported by compiler extension. I think it's
easier now to do compiler extensions, with clang's support machinery.
But the last time I tried my hand at that, with gcc (for an idea about
exception handling), I found that gcc had a really complex structure
expressed in the apparently lowest possible level K&R C...

• • •

Regarding the claim of hard to see type, consider

auto s = "Blah";

Until I learned this as a special case (that didn't take long, but
until) I thought this would deduce `s` as `char const[5]`, which is
non-assignable and with length. But it deduces `s` as `char const*`.
Which is not even a constant, so one can, perhaps inadvertently, do

s = "Oh!";

Well, then perhaps change the declaration to

auto s[] = "Blah"; // ?

But contrary to what I think is a natural expectation, one just can't
use `auto` for an array item type: that won't compile.

The /technically/ correct way when one desires `s` as an immutable array
with length information retained, as the initializer, is to write

auto& s = "Blah";

But I wouldn't do that because it just obscures the desired result.

With the pseudo-keywords one can, however, write quite naturally

$let s = "Blah"; // `s` is const, decayed to pointer
$var s = "Blah"; // `s` is variable, decayed to pointer
$name s = "Blah"; // `s` is `char const[5]`

where

• $let → auto const, always yielding just a constant /value/;

• $var → auto, always yielding a mutable /variable/; and

• $name → auto&, always yielding just an /alias/.

Still lacking is a way to express

decay_t<decltype( *"Blah" )> s[] = "Blah";

which yields a mutable array, `char[5]`. A macro for this would get
/too/ ugly not just because it would have to take the initializer as
argument, but because that initializer could easily contain a comma or
two, which would be interpreted as macro argument separators. Well, a
variadic macro would be able to handle that, but it would still be ugly.

• • •

As an example of a problem that as far as I can see is not generally
solvable with keywords, consider the following code:

template< class Some_type >
using ref_ = Some_type&;

template< class Stream >
auto int_from( ref_<Stream> stream )
-> int
{
int result;
stream >> result;
if( stream.fail() ) { abort(); }
return result;
}

auto input_int( ref_<const wstring> prompt )
-> int
{
wcout << prompt;
return int_from( wcin ); // <--- Deducing the type Stream.
}

That works fine.

But the second declaration here does not work fine:

void foo()
{
auto& yep = wcin;
ref_<auto> nope = wcin; // <--- Uh oh.

(void) yep; (void) nope;
}

The problem here isn't the reference, which is just one specific use
case, it's the use of `auto` as a template (alias) argument.

The good old general template argument type deduction can see right
through that little template alias, as in the `ref_<Stream>`, but `auto`
just doesn't cut it.


> Why do you prefer obfuscation to idiomatic C++? What you are doing
> try to make C++ code look like code from other inferior languages is
> really egregious.

Well, those are emotional reactions.

I don't share them. :)

Actually I felt happy being able to express how I think about things
(just also slightly annoyed at having to use evil macros etc.).

For re the inferior languages, I think that to use C++ in a good way one
must have a clear picture of what /hypothetical language constructs/,
usually very much like constructs from other languages that one has
used, one is trying to implement with one's C++ code.

For example, to me, header and implementation files, and the whole thing
with include guards etc., implements modules, like Modula-2 MODULE or
Pascal UNIT or Ada PACKAGE. I haven't really used Ada but I've read some
books about it. And for example, to me, my `i_up_to` for a range-based
loop, implements in an imperfect but practically useful way, Python 2.7
`xrange` or Python 3.x `range`. And correspondingly, e.g. the $let
pseudo keyword in the expressive dialect implements in a very restricted
and awkward, but IMHO still very practically useful, way, a logical
`let` from a functional language or maths.


Cheers!,

- Alf

Mr Flibble

unread,
Feb 23, 2017, 8:18:24 PM2/23/17
to
Apart from yourself who are you trying to convince? Really bad.

/Flibble



Alf P. Steinbach

unread,
Feb 23, 2017, 9:17:50 PM2/23/17
to
On 24.02.2017 02:18, Mr Flibble wrote:
> Apart from yourself who are you trying to convince? Really bad.

I replied because you asked. Now you quoted everything just to point out
that you can't remember asking, and you wonder who. That's dumb.

Cheers!,

- Alf

Alf P. Steinbach

unread,
Feb 23, 2017, 11:27:30 PM2/23/17
to
On 24.02.2017 01:33, Stefan Ram wrote:
> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>> I decided to do a little challenge we used to give to the students in
>> Bodø in the mid 1990s: to implement a bignumber class and use it to
>> compute the Fibonacci sequence up to a ridiculous length.
>
> I did not really try to find the bug in your code, but I
> wrote a C++ program to print the 100'000th Fibonacci number.
>
> Disclaimer: it's a quick hack: One cannot really change the
> »< long, 1'000'000'000L >« below to something else, unless
> on also edits the »"000000000"« in »to_string«.
>
> Disclaimer: Code was slightly edited between the last test
> and the post, hope not to introduce new bugs.
>
> #include <algorithm>
> #include <cassert>
> #include <climits>
> #include <cmath>
> #include <cstdlib>
> #include <initializer_list>
> #include <iostream>
> #include <ostream>
> #include <string>
>
> using namespace ::std::literals;
>
> /* a vector that will grow on demand */
> template< typename T >
> class vector : public ::std::vector< T >
> { public: using ::std::vector< T >::vector;
>
> /* delete the following function definition when your estimates for
> the number of digits in main are surely large enough (to trade some
> security for speed) */
> T& operator[]( typename vector::size_type const i )
> { while( i >= this->size() )this->push_back( 0 );
> return( *( static_cast< ::std::vector< T >* >( this )))[ i ]; }};
>
> /* a big number */
> /* base must be less than MAX_DIGIT/2, say less than MAX_DIGIT/2-2,
> base must be a power of 10 for the simplistic to_string function
> below to be correct. */
> template< typename DIGIT, DIGIT base >
> class bignum : public vector< DIGIT >
> { public: public: using vector< DIGIT >::vector;
> using digit_type = DIGIT;
> typename ::bignum<DIGIT,base>::size_type length;
>
> /* add h to g giving R,
> h must not be shorter than g,
> R is the result */
> static void sum
> ( ::bignum<DIGIT,base> & g, ::bignum<DIGIT,base> & h,
> ::bignum<DIGIT,base> & R )
> { typename ::bignum<DIGIT,base>::size_type p = 0;
> bool o = false; /* actually the carry bit */
> while( p < g.length )
> { DIGIT const s = o + g[ p ]+ h[ p ];
> R[ p++ ]= s -( o = s > base )* base; }
> while( p < h.length )
> { DIGIT const s = o + h[ p ];
> R[ p++ ]= s -( o = s > base )* base ; }
> if( o )
> { DIGIT const s = o;
> R[ p++ ]= s -( o = s > base )*base; }
> R.length = p; }
>
> static ::std::string to_string( ::bignum<DIGIT,base> & n )
> { ::std::string result; result.reserve( 1000 );
> for( int i = n.length; i > 0; )
> { --i;
> if( i == n.length - 1 )result += ::std::to_string( n[ i ]);
> else
> { ::std::string s = ::std::to_string( n[ i ]);
> char const * p = "000000000" + s.length();
> result += p; result += s; }}
> return result; }
>
> /* set the argument to the number one */
> static void one( ::bignum<DIGIT,base> & x )
> { x[ 0 ]= 1; x.length = 1; }};
>
> int main()
> { using number = bignum< long, 1'000'000'000L >;
> number x( 30'000 ); number::one( x );
> number r( 30'000 ); number::one( r );
> number R( 30'000 ); number::one( R );
> number a;
> for( long i = 2; i <= 100'000; ++i )
> {
> bool print = i == 100'000; /* edit here to specify which values */
> /* you want to be printed. */
> if( print )
> { ::std::string result = number::to_string( r );
> ::std::cout << i << ' ' << result << '\n'; ::std::cout.flush(); }
> if( r.length < x.length )number::sum( r, x, R );
> else number::sum( x, r, R );
> a = ::std::move( R );
> R = ::std::move( x );
> x = ::std::move( r );
> r = ::std::move( a ); }}

Oh. :)

I confirmed, by writing my own little program for that, that you get a
correct result. Although it is for index 999.999 in the sequence, when
one considers fib(0) = 1, fib(1) = 1, fib(2) = 2, fib(3) = 3 and so on.

I'm not sure how your code works, it seems to do strange things, but
here's the expressive C++ dialect code that I cooked up to test it and
show how I would have written that program:


[code]
#include <p/expressive/using_weakly_all.hpp>

#include <algorithm>
#include <iostream>
#include <math.h> // log
#include <vector>
using namespace std;

using Big_int = std::vector<int>; // Each item is a decimal digit.

$procedure add_to( ref_<Big_int> a, ref_<const Big_int> b )
{
$let size_a = n_items_in( a ); $let size_b = n_items_in( b );
$var carry = 0;
for( $each i $in i_up_to( max( size_a, size_b ) ) )
{
if( i >= size_a ) { a.resize( i + 1 ); }
a[i] += carry + ($when( i < size_b ) $use( b[i] ) $default_to(
0 ));
carry = a[i]/10;
a[i] -= 10*carry;
}
if( carry != 0 ) { a.push_back( carry ); }
}

$just
{
$let golden_ratio = 1.6180339887498948482045868343656;
$let n = 100'000;
$let n_digits = static_cast<int>( (n + 10)*log10( golden_ratio ) + 1 );
clog << n_digits << " digits expected.\n";

$var a = Big_int{1}; a.reserve( n_digits );
$var b = Big_int{0}; b.reserve( n_digits );
for( $n_times( n ) )
{
$var next = a;
add_to( next, b );
a = move( b ); b = move( next );
}
for( $each digit $in reverse_span_of( b ) ) { cout << digit; }
cout << endl;
}
[/code]

I did not take the trouble to split the addition loop into parts where
the processing could be specialized for speed; I just used `-O3`. ;-)

This might be the reason that this code is shorter, 43 versus 91 lines,
even though my code looks much more verbose and whitespacey-ish.


Cheers!,

- Alf

PS: One problem with the $n_times macro is that g++ produces a very much
undesired warning “-Wno-unused-but-set-variable”. I just turn it off but
I would like to suppress it for this situation in the code. I tried with
`_Pragma` expressions in the macro but g++ would have none of that
inside a `for` loop head. The macro is currently defined as
`$e::Dummy_reference_consumer $unique_temp_name $in $e::i_up_to( n )`. I
can't think of a way to do that without a range based loop.

Robert Wessel

unread,
Feb 24, 2017, 2:18:55 AM2/24/17
to
On 24 Feb 2017 02:58:43 GMT, r...@zedat.fu-berlin.de (Stefan Ram)
wrote:

>r...@zedat.fu-berlin.de (Stefan Ram) writes:
>>I did not really try to find the bug in your code, but I
>>wrote a C++ program to print the 100'000th Fibonacci number.
>
> I wrote a similar program in JavaScript:
>
> Turns out: Here the JavaScript program is not much
> slower than the compiled C++ program. The C++ program
> takes about 1 second here and the JavaScript program about
> 1.4 seconds. And this was only in Firefox, Chrome might
> even be faster. Amazing what they can get out of
> interpreters today!


The better Javascript processors are JITs these days.

Tim Rentsch

unread,
Feb 24, 2017, 3:08:29 PM2/24/17
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:

> [code in "expressive C++ dialect"]
>
> I can't see anything wrong, and (1) everything works just fine for the
> first 121 Fibonacci numbers, and (2) the asserts don't trigger.
>
> I'm baffled by my own bug.
>
> Which is possibly in the subtraction operator or something, but I'm
> exhausted & hungry; I'll eat and watch a movie, and see tomorrow if
> anyone saw something blindingly obviously wrong?

I think some other replies have let you find the bug. I
just wanted to add my vote for using regular C++ rather
than the "expressive" flavor when posting this kind of
stuff. To look at any code more than about 10 or 20
lines I would like to be able to compile it. If the
code is written in "expressive" C++ I can't do that.

Öö Tiib

unread,
Feb 24, 2017, 6:39:26 PM2/24/17
to
+1

If we need compiling language with "var" and "let" and "func" then we
can take rust or swift; there are no need to mutate C++ into one of
those.

Attempts to mutate C++ into different language by using preprocessor
and template meta-programming tricks are not too good. I have tried to
use such things but all immersion went immediately away when there was
some typo in my code.

The compiler typically did not point at the typo of mine but spit several
rather incomprehensible pages of gibberish about something being wrong
with internals of those meta-programming tricks. That just confused,
wasted time and improved nothing.

Mr Flibble

unread,
Feb 25, 2017, 5:17:01 PM2/25/17
to
Also use of dollar sign ($) in identifiers is implementation defined and
thus non-portable and to be avoided.

/Flibble

Alf P. Steinbach

unread,
Feb 25, 2017, 7:52:28 PM2/25/17
to
I've posted the current version of Expressive C++ on GitHub:

<url: https://github.com/alf-p-steinbach/Expressive-Cpp>

It uses a really tiny macro library, Macro Magic, that I also posted:

<url: https://github.com/alf-p-steinbach/Macro-Magic/>

Both libraries are header only and designed to be placed in a common `p`
directory in the compiler's include path. `p` is my middle name
shortened to one letter, and it's also short for “progrock”.

Not sure exactly where to take this but it fills my free time.

And considering that you offered (if memory serves me!), I would be very
grateful if you could take over the balanced tree tutorial.

Another reason for that, if you have time, is that you evidently are
familiar with the subject, knowing stuff that I didn't know. ;-)


Cheers!,

- Alf

Juha Nieminen

unread,
Feb 27, 2017, 3:46:00 AM2/27/17
to
Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
> I decided to do a little challenge we used to give to the students in
> Bodø in the mid 1990s: to implement a bignumber class and use it to
> compute the Fibonacci sequence up to a ridiculous length.

People will scoff at people for posting eg. Windows-only code that uses
non-standard libraries exclusive to Windows. And you expect people to
just accept your custom dialect?

Alf P. Steinbach

unread,
Feb 27, 2017, 4:00:06 AM2/27/17
to
On 27.02.2017 09:45, Juha Nieminen wrote:
> Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
>> I decided to do a little challenge we used to give to the students in
>> Bodø in the mid 1990s: to implement a bignumber class and use it to
>> compute the Fibonacci sequence up to a ridiculous length.
>
> People will scoff at people for posting eg. Windows-only code that uses
> non-standard libraries exclusive to Windows.

Where did you see any Windows code?


> And you expect people to
> just accept your custom dialect?

You can try it out.

<url: https://github.com/alf-p-steinbach/Expressive-Cpp/>

I think I'm honing in on a quite useful dialect, but since this is the
first time I do something like this there must surely be much room for
improvement, that people can suggest. :)

Note: the documentation is the bare minimum so far, but it should be
sufficient to get up and running (after all it's a pure header library).


Cheers!,

- Alf

Juha Nieminen

unread,
Feb 27, 2017, 6:26:29 AM2/27/17
to
Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
> On 27.02.2017 09:45, Juha Nieminen wrote:
>> Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
>>> I decided to do a little challenge we used to give to the students in
>>> Bodø in the mid 1990s: to implement a bignumber class and use it to
>>> compute the Fibonacci sequence up to a ridiculous length.
>>
>> People will scoff at people for posting eg. Windows-only code that uses
>> non-standard libraries exclusive to Windows.
>
> Where did you see any Windows code?

I don't think that what I wrote is that hard to understand.

If Windows-specific non-standard code is frowned upon, then why do you
expect your custom non-standard language extension be treated any better?

>> And you expect people to
>> just accept your custom dialect?
>
> You can try it out.

And I can try Windows-specific code out. But that doesn't make one
iota of a difference with regards to what I said.

Alf P. Steinbach

unread,
Feb 27, 2017, 7:36:43 AM2/27/17
to
On 27.02.2017 12:26, Juha Nieminen wrote:
> Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
>> On 27.02.2017 09:45, Juha Nieminen wrote:
>>> Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
>>>> I decided to do a little challenge we used to give to the students in
>>>> Bodø in the mid 1990s: to implement a bignumber class and use it to
>>>> compute the Fibonacci sequence up to a ridiculous length.
>>>
>>> People will scoff at people for posting eg. Windows-only code that uses
>>> non-standard libraries exclusive to Windows.
>>
>> Where did you see any Windows code?
>
> I don't think that what I wrote is that hard to understand.
>
> If Windows-specific non-standard code is frowned upon, then why do you
> expect your custom non-standard language extension be treated any better?

Oh. I never expect good treatment. I just offer of myself, what I have,
because I believe in communication and positive sum interactions.

Again, you can just try this, it's available at GitHub

<url: https://github.com/alf-p-steinbach/Expressive-Cpp>

I have only compiled it in Windows though, and there's almost a law that
what one has not actually tried, /will/ manage to surprise... ;-)


Cheers!,

- Alf

Scott Lurndal

unread,
Feb 27, 2017, 8:37:26 AM2/27/17
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:

>> And you expect people to
>> just accept your custom dialect?
>
>You can try it out.

Why should we? What possible benefit does it have?

Alf P. Steinbach

unread,
Feb 27, 2017, 8:50:16 AM2/27/17
to
I was replying to Juha; I don't know who you represent, Scott. I'm not
asking or begging people to try this. That would be really stupid. I was
pointing out, to Juha, in an ongoing conversation, that in order to
discuss this library or C++ dialect (whatever), in an informed way, one
can simply try it out first. That's what I generally do myself, and I
think it's a sensible approach also for others. ;-)

Cheers & hth.,

- Alf

Scott Lurndal

unread,
Feb 27, 2017, 11:56:01 AM2/27/17
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>On 27.02.2017 14:37, Scott Lurndal wrote:
>> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>>
>>>> And you expect people to
>>>> just accept your custom dialect?
>>>
>>> You can try it out.
>>
>> Why should we? What possible benefit does it have?
>
>I was replying to Juha; I don't know who you represent, Scott.

I'm honestly asking what is the benefit of this
macro-based language built on C++.

Mr Flibble

unread,
Feb 27, 2017, 3:27:46 PM2/27/17
to
On 27/02/2017 16:55, Scott Lurndal wrote:
> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>> On 27.02.2017 14:37, Scott Lurndal wrote:
>>> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>>>
>>>>> And you expect people to
>>>>> just accept your custom dialect?
>>>>
>>>> You can try it out.
>>>
>>> Why should we? What possible benefit does it have?
>>
>> I was replying to Juha; I don't know who you represent, Scott.
>
> I'm honestly asking what is the benefit of this
> macro-based language built on C++.

Isn't it clear? Obviously the purpose of "expressive C++ dialect" is to
irritate the fuck out of people especially on Usenet.

/Flibble


Alf P. Steinbach

unread,
Feb 28, 2017, 5:58:52 AM2/28/17
to
On 2/27/2017 5:55 PM, Scott Lurndal wrote:
>
> I'm honestly asking what is the benefit of this
> macro-based language built on C++.

In the Expressive C++ announce posting I wrote that “It implements a
less unsafe, more convenient and readable-for-non-C++-expert-folks
dialect of C++”.

I think it's best to think of it as simply a dialect of C++, since just
saying “macro-based” makes people think of shouting uppercase macros,
and of lowercase macros that can conflict with other names, and so on.
And it's not like that at all. Although it can become that if it enjoys
some but not enough success and others start using the $ sign in names.

Anyway, if you ask for the benefit(s) of e.g. Python, you'll get O(n)
different answers where n is the number of Python practitioners.

And as yet there is only 1 practitioner of Expressive C++, and it's a
new thing, still changing: an ongoing exploration. And that means that
anything that I say is not necessarily representative of what could-be
other practitioners would say, and it could be outdated just days after
I wrote it. E.g. I started out writing `$procedure` for a `void`
function; then I felt that that was too verbose and changed it down to
`$proc` in the current version; but that was a cowardly compromise, not
having the courage of my conviction about what's most important, so as
soon as Visual Studio finishes updating, which it's been busy doing the
last hour or so, I'll change it further down all the way to just `$p`.

The rationale for that change is the same as in early C, that what one
uses the most should be the least to read and write. The much used stuff
is recognized anyway. It doesn't need to be self-descriptive, but `$f`
and `$p`, while less to write and read than `auto` and `void`, do have
mnemonic value, and they don't have other meanings: they're
non-contextual, which is nice both for non-expert humans, and editors.

So, I've expended some effort on making the code shorter, that is,
terseness, which therefore seems to be a benefit to me, one that comes
in addition to the safety, convenience and readability benefits.

But consider this ¹story about Benjamin Franklin:


“Crippled by gout, the great scientist nonetheless wanted to be on hand
for the first manned balloon flight. Tens of thousands went out to
Versailles to see the Montgolfier brothers set off the flame that would
heat the air in their gaily-colored balloon. People gasped to see the
ascent. Some women fainted.

Then, someone spied the 79-year old Dr. Franklin taking it all in from
his carriage. It's a wonder, to be sure, the questioner said, "but of
what practical use is it?" Ben Franklin was the man to ask. He was the
most practical man in the world.

Smiling, Ben answered: "Of what practical use is a newborn baby?"”


He saw an open-ended potential.


Cheers!,

- Alf

¹ <url:
http://www.frcblog.com/2013/01/ben-franklin-january-17-1706-what-use-newborn-baby/>

leigh.v....@googlemail.com

unread,
Feb 28, 2017, 7:22:07 AM2/28/17
to
You've made your virtual keywords shorter? The problem isn't length or terseness the problem is one of obfuscation and in fact single letter virtual keywords are even more obfuscated than longer ones.

We need a new abbreviation for your egregious code:

to;dr

Too obfuscated didn't read.

/Leigh

Daniel

unread,
Feb 28, 2017, 2:30:53 PM2/28/17
to
On Tuesday, February 28, 2017 at 5:58:52 AM UTC-5, Alf P. Steinbach wrote:
>
> Ben answered: "Of what practical use is a newborn baby?"”
>
Hmmm ... it seems to me that that quote would be more apropos if you were
inventing a new programming language, or such. Of course, anyone willing to
work for free can do anything that they like. But did you have to work on this!

:-) Be well,
Daniel

Vir Campestris

unread,
Mar 1, 2017, 4:44:38 PM3/1/17
to
On 28/02/2017 10:58, Alf P. Steinbach wrote:
> In the Expressive C++ announce posting I wrote that “It implements a
> less unsafe, more convenient and readable-for-non-C++-expert-folks
> dialect of C++”.
Alf, I like your posts, and I respect your advice. But I found your
Expressive code impossible to read. It requires knowledge of all sorts
of things that I don't know, and I don't have time to read.

It's not C++.

I come here to keep my hand in, when my current job is 90% C. I want to
read about C++.

<snip>
> So, I've expended some effort on making the code shorter, that is,
> terseness, which therefore seems to be a benefit to me, one that comes
> in addition to the safety, convenience and readability benefits

Be careful. Remember APL...

Andy

Alf P. Steinbach

unread,
Mar 1, 2017, 11:17:42 PM3/1/17
to
On 3/1/2017 10:44 PM, Vir Campestris wrote:
> On 28/02/2017 10:58, Alf P. Steinbach wrote:
>> In the Expressive C++ announce posting I wrote that “It implements a
>> less unsafe, more convenient and readable-for-non-C++-expert-folks
>> dialect of C++”.
> Alf, I like your posts, and I respect your advice. But I found your
> Expressive code impossible to read. It requires knowledge of all sorts
> of things that I don't know, and I don't have time to read.

I've tried to make the About section short, informative and clear,

<url: https://github.com/alf-p-steinbach/Expressive-Cpp#about>


> It's not C++.
>
> I come here to keep my hand in, when my current job is 90% C. I want to
> read about C++.
>
> <snip>
>> So, I've expended some effort on making the code shorter, that is,
>> terseness, which therefore seems to be a benefit to me, one that comes
>> in addition to the safety, convenience and readability benefits
>
> Be careful. Remember APL...

Yes. Easily recognized as gibberish. :) Thanks.


Cheers!,

- Alf

Tim Rentsch

unread,
Apr 16, 2017, 11:52:52 AM4/16/17
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:

> On 24.02.2017 21:08, Tim Rentsch wrote:
>> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>>
>>> [code in "expressive C++ dialect"]
>>>
>>> I can't see anything wrong, and (1) everything works just fine for the
>>> first 121 Fibonacci numbers, and (2) the asserts don't trigger.
>>>
>>> I'm baffled by my own bug.
>>>
>>> Which is possibly in the subtraction operator or something, but I'm
>>> exhausted & hungry; I'll eat and watch a movie, and see tomorrow if
>>> anyone saw something blindingly obviously wrong?
>>
>> I think some other replies have let you find the bug. I
>> just wanted to add my vote for using regular C++ rather
>> than the "expressive" flavor when posting this kind of
>> stuff. To look at any code more than about 10 or 20
>> lines I would like to be able to compile it. If the
>> code is written in "expressive" C++ I can't do that.
>
> I've posted the current version of Expressive C++ on GitHub: [...]

I still cast my vote for using regular C++ rather than the
"expressive" flavor. I suppose I could get your libraries and go
to the trouble of making them available for compiling your code,
but in practical terms I know I'm not going to. Plus, the
newsgroup here is supposed to be primarily about C++, and code
written in "expressive C++" kind of detracts from that.

> And considering that you offered (if memory serves me!), I would be
> very grateful if you could take over the balanced tree tutorial.

My offer was just to explain how threading works (I already gave
an explanation of how balancing works). My reason for wanting to
see the tutorial continue is to see how you would write it in C++.
I understand the algorithm, but I want to get more exposure to
current C++ style.

> Another reason for that, if you have time, is that you evidently are
> familiar with the subject, knowing stuff that I didn't know. ;-)

I didn't when I started. Plus, if you write the code yourself,
you will get the benefit of both having figured it out yourself
and (presumably) my comments on the result. If I finish it you
won't get either of those (and I won't get the benefit of seeing
how you would do it).
0 new messages