C++ port of Doom from C

The Partridge Family were neither partridges nor a family. Discuss.
User avatar
MyK_00L
Posts: 19
Joined: June 21st, 2016, 10:44 am

Re: C++ port of Doom from C

Post by MyK_00L » April 20th, 2020, 7:09 am

Well, the functional side of Rust pretty much boils down to functions on iterators, and they are optimized really well, as https://doc.rust-lang.org/book/ch13-04-performance.html suggests it pretty much compiles to the same stuff you would write iteratively. And iterators evaluate stuff lazily, which is pretty cool imo.

Also being Rust relatively new, it is much cleaner in many aspects, for example the basic types names.
Compilation error messages are good, unlike gcc's

Another cool thing is all libraries can be found in one place (https://crates.io) and documentation is automatically built at https://docs.rs

I don't use the functional side much, but parsing a file like this felt pretty good

Code: Select all

v.extend(std::fs::read_to_string(filename).unwrap().split('\n').map(|s| s.split(' ').collect::<Vec<&str> >()[0].to_string()).filter(|s| s.len()>=min_len).take(n));
There are some strange things, like you don't have random in the standard library, but given how easy it is to import a crate (library), I don't really care.
Plus some of the crates provided are really cool, like serde, serializing json (or anything) into a strongly typed struct is very useful.
The only thing I really wish was ready now is a good GUI framework, but I guess I'll have to wait.

As for the pattern matching of types, I had never really seen std::variant, but from a quick glance it looks like a c++ version of unions.
In Rust I guess you would use enums as they can hold stuff inside the elements and can be pattern matched against with match.
idk about pattern matching directly for types, but does it really make sense in a strongly typed language?

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: C++ port of Doom from C

Post by albinopapa » April 20th, 2020, 9:25 am

idk about pattern matching directly for types, but does it really make sense in a strongly typed language?
Well, yes and no. First let me explain what std::variant is and how it works the best I can as I understand it.

You are correct that std::variant is basically a union, but instead of having an integral identifier such as an int or enumeration and manually having to check which object is the active object the compiler tracks it for you. The downside in my opinion is since there is not pattern matching built in.

The implementation uses a integral identifier "an index" that tracks which type. When you create a 'variant' using one of the supplied alternatives in the template argument list, the compiler figures out where in the list that type is: std::variant<int, double, float> var = 42 // the int is at index 0, so the internal index is set to 0 as the active type. To get the value '42' in this case out of the variant, you have a few options.

Use std::get<T> and risk having an exception thrown if the type supplied and the active type don't match.
Use std::get_if<T*> which returns nullptr if the types don't match
Use std::visit( visitor, var ); visitor can be a lambda or a struct that inherits from a list of lambdas or a struct that overloads the operator() for each type supported by the variant
Use std::holds_alternative<T>( var ) to find which type is held, then use std::get<T>( var ) to return the held object.

That is why I think it would be just easier to have a switch<T> or as you said Rust has match{ }
Right now, if you choose a single lambda as a visitor, your options are still have a set of overloaded functions to call and passing in the parameter of the lambda

Code: Select all

std::visit( []( auto&& value_ ){ func( std::forward<decltype( value_ )>( value_ ); }, var );
func( int value_ );
func( float value_ );
func( double value_ );
or use if constexpr/else if constexpr

Code: Select all

std::visit( []( auto&& value_ )
{
    using value_type = std::decay_t<decltype( value_ )>;
    if constexpr( std::is_same_v<value_type, int> )
    {
        // do something with int value
    }
    else if constexpr( std::is_same_v<value_type, float> )
    {
        // do something with float value
    }
    else
    {
        // do something with double value
    }
}, var );
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

Post Reply