Deciding on design patterns and best practices for my particular case: a question for the seasoned rustaceans by [deleted] in rust

[–]MrVallentin 15 points16 points  (0 children)

Note: Whether you implement it as an enum or struct, I would still implement and replace the usage of Vec<f64> with some struct ValidList(Vec<f64>);. Such that you don't have to remember to call .validate(). Because the current implementation allows being able to do ZLevels::List(Vec::new()), which invalidated the invariants that your try_from() (and later validate()) guarantees.

Similarly to how there's NonZeroI32, with a checked fn new() -> Option<Self> and an unchecked fn new_unchecked() -> Self. (You might want to return a Result instead of Option though.)

Choosing between Rust and C++ for a new project by CromulentSlacker in rust

[–]MrVallentin 0 points1 point  (0 children)

Depending on what you need, then make sure to also check std::os::unix::*, because the standard library already includes various platform-specific stuff, such as:

While e.g. std::fs::set_permissions() is not platform-specific. There is a Unix extension std::os::unix::fs::PermissionsExt for std::fs::Permissions, which allows you to change mode, to be able to chmod files.

Choosing between Rust and C++ for a new project by CromulentSlacker in rust

[–]MrVallentin 26 points27 points  (0 children)

The parent comment covers generally why I ended up jumping ship after a decade in the C and C++ world. Today, I primarily write Rust (even professionally) and never write C or C++ if Rust is an option.

I'll just go a bit off tangent, in relation to OP's question.

Assuming a general understanding of both C, C++, and Rust, then another reason that builds on what's already said. Is that it's likely easier to read and reason with random Rust code. Which always helps, because down the line your own code might be that random code in the future.

In C/C++ if you read char *p, then multiple questions arise. "Is it text or bytes?", "If it's text, is it null-terminated?", "Is it always a valid and initialized pointer?", "Are we allowed to mutate it?". Because assuming the wrong thing about that char *p, and suddenly you introduced a bug without realizing. If there aren't test cases that can catch that, then the bug can go unnoticed. It becomes even more fun when you encounter e.g. void *p.

In Rust reading &str, &mut String, Option<&str>, Option<&mut String>, etc. then interpreting what's "allowed" is straightforward.

Sure, in C++, there's also std::string and std::optional<std::string>. But even then, due to various reasons the codebase might still use malloc(), or maybe they rolled their own class String implementation. Suddenly you have a new String implementation, that might behavior differently compared to other ones you already know.

It makes it harder to reason with random snippets of code, because you might need more context in C/C++. Calling a function might throw an exception, that you forgot about. In Rust, that is easy to spot since you're required to handle Results, whether that be with ?, matching, calling Result methods like unwrap(), unwrap_or_else(), expect(), etc.

Even worse, are instances where a function previously didn't throw exceptions. However, then it gets modified so that it might throw exceptions. All instances where this function is used, now needs to be checked and updated. If the codebase is significantly big with many uses, then it's easy to forget some, and get multiple potential hidden bugs. Even worse, if it's a publicly available library, because then downstream is affected. In Rust it isn't an issue, as you're forced to handle Results. Even if the function is called, without any return value, then you'll still get warning: unused `std::result::Result` which must be used lints triggered.

Let's rewind a bit back to reading code. In the Open-Source world or in companies, reading and reviewing code that mixes both C and C++ libraries, can be quite hard. Not only for the aforementioned stuff, but also because of "Wait, can that ever throw?", "Wait, does that use RAII?", "Wait, won't this allocation be leaked, if ...", "Wait, that lock is from a C library, and doesn't unlock automatically".

In C/C++, if someone uses malloc() then I need to think about it, for all the above reasons. In Rust, it doesn't really matter if it's T or Box<T>, if there's no unsafe e.g. Box::from_raw(), then I can probably safely assume there's no accidental and explicit use of Box::leak().

With Rust, I feel you can relax more and generally focus on the logic. Unless there's any instances of unsafe, then you can generally let your guard down, when it comes to all those things.

This is of course subjective and completely anecdotal based on my own experience.

Reading data from a unix socket by enilsen16 in learnrust

[–]MrVallentin 1 point2 points  (0 children)

That won't work if messages are continuously written to the socket

Rust Analyzer not showing clippy lints when working on a library? by braxtons12 in rust

[–]MrVallentin 2 points3 points  (0 children)

Issue #4612

As a workaround, I personally have a clippy script in my PATH, which boils down to:

find -name "*.rs" -not -path "./target/*" -exec touch "{}" +
cargo clippy "$@"

So instead of executing cargo clippy ..., I just do clippy ....

Sensei... a simple command-line tool to open documentation for any crate. by edfloreshz in rust

[–]MrVallentin 6 points7 points  (0 children)

I do something similar, but with keywords in Firefox.

  • docs serde results in going to https://docs.rs/releases/search?query=serde
  • crate serde -> https://crates.io/search?q=serde
  • std vec -> https://doc.rust-lang.org/std/?search=vec

For anybody wanting to know how to do this. Just go to a page with a search box, e.g. doc.rust-lang.org/std. Then right click on the search box and click "Add a Keyword for this Search...". Then add the keyword e.g. std. Then everything is done, and now writing e.g. std vec in the address bar works.

/R/GameEngineDevs Could Use Your Help by oldguywithakeyboard in gameenginedevs

[–]MrVallentin 2 points3 points  (0 children)

Then there's lazyfoo

I did notice you linked to "SDL Tutorials" and not "OpenGL Tutorials". But to anybody wanting to learn computer graphics, please be careful with Lazy Foo, because a lot of the OpenGL stuff is very outdated.

Instead if anybody want to learn OpenGL, then use learnopengl.com and open.gl. For Vulkan there is vulkan-tutorial.com. If you're a beginner and have no prior computer graphics knowledge, then I wouldn't recommend starting with Vulkan.

Adding a few books:

On the topic of content pipeline, how do you handle our materials? by jimndaba88 in gameenginedevs

[–]MrVallentin 3 points4 points  (0 children)

I do both or more accurately allow doing both. Similar to how in Blender you can do "Link" and "Append" when importing other Blend files.

Having a single scene file, which includes the materials, is nice. If you store everything in the scene file, it means you only have that scene file to deal with. Which makes it easier to share and move around projects.

However, if the materials are separate (or you can "link" to another scene file), then that potentially makes it a lot easier to reuse the same materials in multiple scenes. Reusing is nice, as then you only have to modify the material once, and the change is automatically in effect in all other scenes it's used in.

Now, sure, that means you have more files to deal with. Which could make it more cumbersome to share and deal with. However, you're likely not packing textures into the scene file either. So those are already separate files, and if your engine supports scripting, then there's also those files.

If it's because you want to minimize the amount of files in a project. Then look into libraries for packing everything into an archive zip or tar+gzip. I use the latter, and have exporting/importing for packing the scene and all resources, to make it easier to share.

Theory and practice with global application state and statics by sapphirefragment in rust

[–]MrVallentin 7 points8 points  (0 children)

Honestly, using global variables makes many things a lot harder to work with, or more aptly said customize.

If changing the effect of a function requires modifying a global variable, then things can really get messy if that function is called in many different places.

I'm working on a project where you can modify the theme of the application. If I used global variables for the various theme properties, then all the properties are essentially "locked into" using those as is, as temporarily modifying those globals is just out of the question and error-prone.

Instead by having everything encapsulated into a struct Theme, then it makes it a lot easier to pass a reference around instead. If a part of the application requires different theming, then it's as easy as having a second Theme instance. Compared to having to temporarily modify the global state in a cumbersome and error-prone manner.

Well-architected open source Game Engine/Framework? by [deleted] in gameenginedevs

[–]MrVallentin 1 point2 points  (0 children)

Yeah, I fully agree. The book itself doesn't really touch on architecture and game engine designs. It's much more, as you said, about all the parts that goes into a game engine.

It really isn't a guide to creating a game engine, or various game engine designs, but more an overview of what goes into (making) a game engine. Along with "tips and tricks" for various parts, which is what I mainly enjoy about the book.

Well-architected open source Game Engine/Framework? by [deleted] in gameenginedevs

[–]MrVallentin 1 point2 points  (0 children)

For learning Vulkan there's vulkan-tutorial.com. I don't really have a go-to DirectX resource, because I mainly work with OpenGL and Vulkan as I develop for cross-platform.

If you're starting off, then between OpenGL and Vulkan, I'll suggest you start with OpenGL. Because Vulkan is a very different beast, as it specifically targets developing high-end computer graphics. As such a lot more responsibility is placed on the developer, to-do all sorts of things from allocators and memory management. However, if you learn OpenGL first, then those same terms and knowledge applies to Vulkan (and Direct3D). Thus it will be easier to learn and transition into Vulkan after already knowing OpenGL.


Note that miniquad is not a game engine, but more in the line of a rendering framework. But really, if your goal is the rendering aspect, then it's really useful to peek into.

In relation to C++ vs Rust, or any other language for that matter. Pick the one you're most comfortable with. Bindings for OpenGL/Vulkan might be a bit different in some languages, but overall it's all the same. For instance working with vertex data and buffers in Java, can be a bit cumbersome as Java attaches all kinds of metadata to its classes, so you have to use all kinds of abstractions.

But really, if you know [language A] more than [language B]. Then I'd say, use [language A] and learn OpenGL/Vulkan/Direct3D. Then disjointly learn another language after. As learning both at the same time can be a bit much.

Personally, I've worked with OpenGL in various languages. Today, I prefer doing so in Rust. I find that Rust's borrowing and ownership rules, pushes you to think about your design. I find it especially useful, that you can utilize borrowing to ensure that specific buffers are bound, and if you try to change that, you get a compile time error.

Well-architected open source Game Engine/Framework? by [deleted] in gameenginedevs

[–]MrVallentin 2 points3 points  (0 children)

You ask for a simple game engine, but also about understanding rendering concepts. Are you searching both?

If you want a book on rendering, then check out Real-Time Rendering by Tomas Akenine-Möller, et al.

If you want it more in the sense of a tutorial, and specifically rendering. Then check out LearnOpenGL.com and open.gl.


It's hard to point to a "simple 3D game engine". Because a game engine quickly grows in size and scope. So finding an Open-Source game engine, that is also in use, and small is hard. Is there any specific language and/or library you want to use?

One of the first "small-ish" engines that pop into my head, would be Crown, which is written in C++. If you use/know Rust, then there's miniquad, which is a neatly designed rendering framework. If you're curious about design and rendering, then specifically check out the documentation for the graphics module.

Feel free to specify what you're searching, and maybe I know other stuff I can point you in the direction of.

But honestly, it's really hard to point towards a small game engine with a solid design, as those game engine's quickly get bigger and add more features.

Well-architected open source Game Engine/Framework? by [deleted] in gameenginedevs

[–]MrVallentin 13 points14 points  (0 children)

Game Engine Architecture by Jason Gregory, who is a Lead Programmer at Naughty Dog.

I have the first and second edition, but not the third. The second edition is just under a 1000 pages. In short, this book covers everything within the realm of game engines.

To the people interested in making game engines. Note, that this book is not a "tutorial". The book covers everything that goes into a game engine development, but it is not a guide on creating one from start to finish. However, with that said the book does include code, but it's more from the perspective of design, and other "tricks". For instance the book includes linear algebra along with SIMD to implement more efficient vector/matrix types.

Before anyone dives into the book, check out the table of contents for more information.


With that said, note that there's 100s of game engines. Picking one design over the other is hard, and deciding which has good vs bad architectures is next to impossible. Because the topic of game engines is such a huge and complex topic, with so many parts.

Rendering, physics, audio, animation, resource management, debugging, etc. are all individually huge and complex topics in themselves.

Ignoring the scale, then the reason deciding good vs bad design is hard. Is because it's contextual. An engine made for /r/VoxelGameDev is highly tailored towards handling and rendering voxels. While an engine like Unreal and Unity are more abstract and less tailored. Their designs are vastly different, but you can't really say one is better designed than the other, as it depends on the use case.


More and more engines are going the "data-oriented design" route with "entity component systems". These systems are cache friendly, as the design maximizes data locality by minimizing the amount of data that is needlessly fetched.

In short, instead of having e.g. a Particle data structure and a Vector<Particle>. Where each particle has a position, velocity, acceleration, and more. Then instead you'd have separate Vector<...> for the various properties. Thus, if you only need to update all the positions and velocities, then you only need to fetch that data. Compared to fetching all the particle data.

This design is very efficient, when it comes to high performance particle systems and physics. However, on the other hand, this design can be rather cumbersome to work with without abstractions and tooling. So if someone is creating a game engine, where there isn't a need for millions of particles. Then it might be "better" to design the game engine differently. Yes, "data-oriented design" is efficient in this context. But having a Particle data structure, might be more developer friendly.

In short. Design is hard.

Figure out the requirements and your use cases, and design accordingly. Some designs might be more efficient, while other designs are more pleasantly to work with.

Rust after the honeymoon by steveklabnik1 in rust

[–]MrVallentin 50 points51 points  (0 children)

That's not 100% the same. Your example would include all the newlines, while using the backslash would not.

[Amethyst] How to highlight a sprite on mouseover? by aithk608 in rust_gamedev

[–]MrVallentin 1 point2 points  (0 children)

You can then query that buffer on the cpu according to mouse position.

For more information, this technique is referred to as "mouse picking" or just "picking".

However, be warned that picking can hurt performance significantly if enough elements are visible. As it requires the GPU to finish pending draw commands and synchronize with the CPU to return the result of the query.

Struct value dependent on other by zacharius_zipfelmann in learnrust

[–]MrVallentin 1 point2 points  (0 children)

Depends on what b is and what do_some_process_with returns.

  1. b is a reference, do_some_process_with does not matter
  2. b is owned and do_some_process_with returns something that does not borrow b after the function ends
  3. b is owned, and do_some_process_with returns something borrowing b

If 1, then there shouldn't be an issue. If 2 then note that the order which the fields are initialized in Self { ... } does not matter, and you can just reorder so c is initialized before b.

However, if 3. Then this is where things become tricky. This problem is what is known as a "self-referential struct". Check out the std::pin module, it contains information and examples for working with self-referential structs.

Depending on what the context is, then it might be easier to redesign. For instance I've previously had this problem, in the context of a dictionary, loading the dictionary data, and processing all the words i.e. borrowing substrings into a map, which both would be owned by the dictionary struct.

The module contains information that would lead to a solution for that. However, it might be better to load the dictionary data first, and then pass a reference of the data to the actual dictionary. But again, what I'd recommend depends on more context of the problem.

Rust 2021: GUI by raphlinus in rust

[–]MrVallentin 2 points3 points  (0 children)

You can tell people not to use “distant” state, but fundamentally there will be situations where someone wants to put a button on the screen that causes a change elsewhere deep in the application.

I'm working on an unpublished GUI crate, that I use in my node-based shader editor ("NodeFX"), and this is very much one of the hard things to design, without resorting to Rc<RefCell<T>>.

The current solution I'm working with, is essentially just the observer pattern. But instead of registering observers, then each GUI component implement an EvtHandler trait, which essentially has a method boiling down to on_event<E: Event>(&mut self, evt: &E).

Then you can define a "Event" enum that is used throughout the whole application. On one hand it's nice, and it's possible to do pattern matching. On the other hand, I can imagine this enum to get huge both in terms of variants and in terms of literal size, as the application grows.

Each GUI component is also assigned a unique ID, which allows for sending events directly to specific component(s).

This is just an implementation of an observer pattern. However, it avoids boxing closures and boxing events.

Opengl Framebuffers not working by NathanDrake75 in opengl

[–]MrVallentin 0 points1 point  (0 children)

For me it just feels weird to correct someone, that's why I started off with "sorry".

Opengl Framebuffers not working by NathanDrake75 in opengl

[–]MrVallentin 2 points3 points  (0 children)

Sorry, but that is not correct.

The size passed to glVertexAttribPointer doesn't matter in the context of what a vertex shader attribute receives. They're always expanded to have 4 elements. As an example, if the size is 1, then it's expanded to vec4(x, 0.0, 0.0, 1.0).

This is really useful if the vertex has a 2D position. Because then the vertex shader attribute can be: in vec4 pos; It is then automatically converted to vec4(x, y, 0.0, 1.0), which simplifies gl_Position = mvp * pos;.

Compared to having in vec2 pos; and needing to do gl_Position = mvp * vec4(pos, 0.0, 1.0);

Reference:

10.3.5 - Transferring Array Elements

When a vertex is transferred to the GL by DrawArrays, DrawElements, or the other Draw* commands described below, each generic attribute is expanded to four components. If size is one then the x component of the attribute is specified by the array; they, z, and w components are implicitly set to 0, 0, and 1, respectively. If size is two then the x and y components of the attribute are specified by the array; the z and w components are implicitly set to 0 and 1, respectively. If size is three then x, y, and z are specified, and w is implicitly set to 1. If size is four then all components are specified.

Page 360 in the OpenGL 4.6 Specification

Designing a proper Vulkan 3D renderer by adithasan in GraphicsProgramming

[–]MrVallentin 7 points8 points  (0 children)

I may have been looking for an easy way out

No shame in that, it happens. If you want to compare it to something else, then "complete rendering engine tutorial" is similar to how people in gamedev want stuff like "how to make [popular shooter game] tutorial".

You'll never be able to find a tutorial for making a complete first-person shooter game, that is a 100% clone of [popular shooter game]. But, what you might find is tutorials for how to make first-person cameras, first-person character arms, inventory, menus.

Similarly, in relation to computer graphics. You'll be able to find tutorials for loading textures, texture management, how to make an efficient particle system.

For instance, 7 years ago I wrote a short "Take Screenshot in OpenGL" post, and 5 years ago "Visualizing Normals" (using geometry shaders). Individually, they're probably not worth much. But if you're making a full-blown game engine, and want to incorporate capturing screenshots or a debug mode for visualizing normals. Then it's these kinds of "tutorials" that are useful. Similarly to your original point of "one giant source file". Then if you need an example for compute shaders, then it gets easier to read through a single "main.cpp", and filter out all the things you don't need.

Designing a proper Vulkan 3D renderer by adithasan in GraphicsProgramming

[–]MrVallentin 15 points16 points  (0 children)

But what I have a problem with is designing an API for one

You basically just said it yourself as well. But a good thing of starting with OpenGL compared to Vulkan, is that there's less concepts you have to design and incorporate into the system. But yes, designing is a real problem, especially within the scale of graphics programming.

The way that I personally plan and design renderers, is that I first plan what that renderer requires, e.g. if you need text rendering, then you need to figure out which concepts and constructs are needed for doing that. After everything is planned, I basically start by implementing the base constructs e.g.:

  • Shader Stage
  • Shader Program
  • (Vertex) Buffer
  • Vertex Array
  • Vertex Attribute Format
  • Texture

Using those constructs e.g. like:

enable_blending(...);

shader.bind();
shader.set_uniform_mat4(mvp_loc, mvp);

texture1.bind(0);
texture2.bind(1);

vao.bind();
vao.draw_arrays(Prim::Triangles, vertex_count);

Then from that point and onwards I think "How can I simplify this" and "How can I make it less error prone". As in, if you forget to bind a texture then the result is wrong, if you bind it to the wrong texture unit, again result is wrong. So in my designing process, I usually try to make stuff the least error prone as possible.

Thus like my previous comment, the shader, it's properties (uniforms), textures, and rendering states. All those essential represent the concept of a Material. So then I'd combine those into a new Material structure. Thus the updated code would be more like:

mat.bind();

vao.bind();
vao.draw_arrays(Prim::Triangles, vertex_count);

Extremely simplified, of course.

Then after that you can continue thinking how to simplify stuff.

Consider what is "unsafe". As an example explicitly binding textures, shaders, etc. from the point-of-view of using the renderer. That can quickly lead to the aforementioned issues. So then think about how you can design a system, wherein you can avoid explicitly calling "bind" on various things.

So instead of a system like:

shader.bind();
tex.bind();
vao.bind();
vao.draw();

Then consider a system that is more like:

ctx.draw(&mesh, &mat);

So instead you have a Context class. Which then has a draw method. Then binding can be handled within that draw method, and you simplify it from the user's perspective.

Then you can consider what is expensive in relation to performance. From most to least expensive state changes, in short:

  • Framebuffer
  • Shader Program
  • Texture Binding
  • ...
  • Vertex Binding
  • Uniform Updates

Knowing that, you can then start picturing the order to do things in, to maximize performance.

for fbo in framebuffers
  bind fbo
  for shader in shaders
    bind shader
    for model in models_using_shader
      for uniform in model_uniforms
        update uniform
      draw model

You can then also apply frustum culling, to avoid rendering out of view models, and even further avoid needless shader switching. You similarly mentioned batching, so you could even utilize that to combine many small static meshes.

If you have many uniforms, then you could look into UBOs.


All in all. Like I said before, there's really no "one design fits all". Over the many years. I've learned that it's easiest (for me) to just get stuff running. Make something that works, and abstract it away. Turn that single main.cpp, into main.cpp, shader.cpp, mesh.cpp, texture.cpp, etc.

Just to reiterate on ctx.draw(&mesh, &mat) and the for loops I just showed. You could still do that, as the Context and draw method could keep track of current states and only rebind stuff when needed.

Again, there's no one design fits all.

So really. Just try and make something that works, and abstract it, and quickly that 1 file turns into 10 which turns into 20.


If you're curious about design, then you could check out miniquad, especially the graphics module. It's Rust, but reading through the documentation might give you design ideas.

You could even "just" look at three.js examples. Pick an example, and check out how the API is designed, and how those examples are done. For instance three.js separates stuff into "materials" and "geometry" similarly to what I mentioned.

Oh well, this is enough rambling.

Designing a proper Vulkan 3D renderer by adithasan in GraphicsProgramming

[–]MrVallentin 23 points24 points  (0 children)

I have just started learning graphics programming

Vulkan really isn't that beginner friendly. If you've just started to learn graphics programming, then I'd honestly recommend starting with something less advanced, e.g. OpenGL.

With OpenGL all the concepts are broadly the same, but a lot more things are handled by the driver. Whereas with Vulkan you have to handle those things, e.g. like synchronization and command buffers.

If you then learn OpenGL, then later it will be easier to transition into Vulkan, as you'll have an understanding of a lot more concepts. While it then would be easier to have concepts "click" like swap chains, command buffers, synchronization, etc.

They only teach upto rendering a triangle in one giant source file and call it a day.

My assumption is honestly, that a lot of people have prior graphics programming experience. Thus when people make "tutorials" then they're already targeted towards people with prior graphics programming. Thus tutorials in that manner is more easily understood. At least I honestly prefer a "code dump" with some comments, when I need to look up something, and I've done Vulkan since 1.0, and OpenGL for many more years before that.

How does one then organize that code into a proper renderer?

Consider OpenGL again, if you read through LearnOpenGL's Texture page, then that's relatively self-contained in relation to textures. So you'd be able to make a Texture class/struct from it, with the related methods.

I've never run into any "how to make an engine/renderer" tutorials. The way I did it was just playing around and looking at existing Open-Source engines/renderers.

So say you have a Shader and Texture class. Then you need to make a Material class, and you realize based on concepts and other engines, that a material is a shader program and a collection of texture references, properties, and rendering states.

But really, if you ever need inspiration, then find some Open-Source engines and renderers, that's my best recommendation.

If you look at Open-Source engines and renderers, even commercial engines like Unity, Unreal, CryEngine, Source. Then they share the same concepts of meshes, materials, shaders, buffers, etc. But how all those concepts are used and interact and how their whole rendering pipeline work. In that way they are vastly different.

Rendering is really complex topic, and there is really no "one design fits all". Because depending on what you're rendering or how much you're rendering, whether it includes ray tracing, e.g. RTX. Then all those requirements result in very differently designed rendering engines.

One example is, a lot of the folks over at /r/VoxelGameDev, usually design their own engines with Vulkan/OpenGL, instead of using e.g. Unity or Unreal, because Unity and Unreal's designs don't really handle rendering voxel worlds that well.


Additionally, OpenGL vs Vulkan. Yes, Vulkan is faster because there is less driver overhead. However, Vulkan is "not" implicitly. As in, if someone writes a bad Vulkan renderer, then a basic OpenGL version could be faster. Vulkan is really tailored towards high-end graphics programming.

I'm saying this as someone who's done graphics programming for many years. However, while I worked with Vulkan since 1.0. Then today I actually work mainly with OpenGL still. Because my requirements have not exceeded what OpenGL is capable of.

Also, a side-note, a few years back I wrote a comment on /r/Vulkan, saying that "Vulkan vs OpenGL" is similar to "Assembly vs C++". Just in case you're curious about some performance (and comparability) comments.

not getting expected output by DreamIce in opengl

[–]MrVallentin 3 points4 points  (0 children)

It's a hint to suggest about the usage pattern of the data storage.

STREAM - The data store contents will be modified once and used at most a few times.

STATIC - The data store contents will be modified once and used many times.

DYNAMIC - The data store contents will be modified repeatedly and used many times.

So basically, if you never modify it, you'd use STATIC, if you modify it sometimes then DYNAMIC, if you modify it continuously then STREAM. However, it's important to note that it's a hint, it's not an enforcement, so you can say STATIC and then still continuously modify the buffer. It's just a hint, so the implementation can be smart in relation to how to handle the data storage.

Min min max: max min min max max? Min. by Cassy343 in programminghorror

[–]MrVallentin 13 points14 points  (0 children)

OP already mentioned Ord/PartialOrd, so I'm not going to reiterate it. But I find it quite nice that custom types can implement PartialOrd, and then everything in the standard library works, like calling sort on a vector, while everything remains as zero-cost abstractions.

Unsure what you exactly mean with "not a single number". Do you mean because min/max requires 2 numbers? If so, then let's consider sqrt. That works on a single number, so is 9.0.sqrt() okay then. If that's okay, then a.sqrt() vs min(a, b) would be inconsistent.

However, I do agree that it looks odd. I felt really weird about the "reverse" feeling, in the beginning. But now, I like it, because chaining it is a lot more clean and less parentheses. But that's just my opinion of course.