Allow any language literal to boxed Any

Maybe we could be able to use:

  • Numeric literal
  • String literal
  • vec! literal
  • Any possible future map! literal
  • Array literal
  • Boolean literal

... to initialize types like Box<dyn Any>, Rc<dyn Any> and Arc<dyn Any>.

As for the string literal:

At the moment this seems more benefitial for strings:

use std::any::Any;
let s: Box<dyn Any> = Box::new("some string".to_owned());

Compare this to:

use std::any::Any;
let s: Box<dyn Any> = "some string";

This means several contexts (even deep ones) will accept a string literal without much typing.

Not for non-literals

For non-literals, you continue using Box::new or Box<_>::new.

If this were allowed, this has some bad things:

  • It hides the allocation of the Box, Rc or Arc.

For literals, too, it hides the allocation of a Box, but it's a literal: a literal is constructed on the fly, just as well as its Box, so it doesn't hurt for Rust to support it, I guess?

For example, this seems idiomatic:

let _: Box<dyn Any> = vec! ["some string"];

This doesn't seem and wouldn't compile with the above suggestion:

let previous_vector = vec! ["some string"];
let _: Box<dyn Any> = previous_vector;

Object and Union literal

I forgot about C {}, C, C(...) and (...) literals. What do you think?

let o: Arc<dyn Any> = C1;
let o: Arc<dyn Any> = C2(item1, item2);
let o: Arc<dyn Any> = C3 {field: value};
let o: Arc<dyn Any> = (element1, element2);
1 Like

I don't understand why Box<dyn Any> should be easier to construct Tha Box<i32>, nor why the concern of hiding allocations is different for literals compared to values (say, an i32) created in any other way, since the allocation, and moving the value into the Box, must happen at run time anyways, in either case.

4 Likes

Right, but it gets clearer in my opinion. I'd rather just type 0 than Box::new(0). How less characters, the better.

It depends. What if you've a meta-data pairing strings to arbitrary data?

As far as I'm aware, we don't generally follow this rule in Rust very much, and only the desire to save keystrokes is usually not considered very convincing.

That being said, in cases where you do need a lot such values, and thus want to be as concise as possible, you can always easily go down all the way to single-letter function names, like f(0), where f could be some fn f<T: Any>(y: T) -> Box<dyn Any>.

If you have lots of type-erased values from literals, you could also consider working with the allocation-free &'static dyn Any - or maybe even a hybrid approach with an Enum. With implicit coercion, &'static dyn Any is as easy to construct as &0.

8 Likes

In my case I've thought of a node tree similiar to DOM elements. I'll support user "attributes", but called meta-data instead, where each one maps a String to a Box<dyn Any>. I'd like to support any type as a meta-data entry value, so using a custom type for that will be annoying...

To clarify, I meant something like

enum Data {
    Literal(&'static dyn Any),
    Allocated(Box<dyn Any>),
}

Feel free to give it a Deref and whatever else might seem useful.

But that was just a side note, with the main point being that allocation at run-time for literals (like the number 0) isn't really necessary, and IMO use-cases that want it explicitly, might as well do it explicitly.

The problem of that is that I can't have meta_data: Map<String, impl Into<Data>>, or I'll have to do fn set_meta_data(key: String, value: impl Into<Data>) for ex

I could create a custom map, but why would I have to do this?

This is the justification for these much-maligned features in js:

  • Automatic semicolon insertion
  • Automatic coersion, e.g. '1' + 2 == '12'
  • Arithmetic involving non-existent fields isn't an error
  • Many more than I can remember

You already can't mess a char like that with a number. You can't also do Any + Whatever

My point is that saving keystrokes tends to lead towards poor language design choices.

1 Like

There are somethings to consider:

  • These boxed types are standard and stable (if no_std is used, then that type inference should not be considered)
  • This will not require you to use that syntax. It's optional.

Box<dyn Any> , Rc<dyn Any> and Arc<dyn Any>

One of my annoyances is that since Box is known by the compiler, and since it and other std library types use unstable features, they get magical properties that containers in other libraries don't get. You're trying to extend the set of magic properties.

If a feature like this were to happen, the path that aligns with the rest of the language would be making literals generic, e.g. converting to any type that implements From<&'static str>. Thus it wouldn't be any magic for Box or Box<dyn Any>.

However, regardless of how it is implemented, it would break type inference for everything that is generic over &str ā€” for example, PathBuf::new("/usr") ā€” unless there was also type-defaulting like numeric literals currently have, such that the literal is assumed to be an &'static str if nothing else constrains the type.

This would in some cases be a very useful feature to have, but it would come at a complexity cost that affects programs that don't use it.

8 Likes

They might be in the standard library, but they're rarely used and I wouldn't consider them to be part of idiomatic Rust. Given the niche code this would reduce the syntax in, I don't see why Box<dyn Any> should have language support (currently AFAIK it's pure library code, built on top of the language provided TypeId).

1 Like

For a node API similiar to the browser API for DOM elements (with a limited set of variants), it will be common to see Arc.

Other than that, I've an idea of using both a node API and a UI component API, where components are defined by the user, similiar to React.

I've been wondering all this time though if I should use a simpler language like Swift or Go. What always worried me is the platform support, but I think using WebAssembly may turn it possible...

I'm also wondering what's the goal of creating a game engine for Rust for instance then? Sure, Rust is used for embedded programming, but it's a generic language still.

That has nothing to do with Box<dyn Any> though. I have built a similar virtual-dom system before which ended up using a lot of Arc<dyn Render> internally, having a shorthand for Box<dyn Any> doesn't help that.

1 Like

Well, you said these boxed types are "rarely" used, not specifically Box<dyn Any>

Given this thread was about boxed Any I assumed "these boxed types" referred to it.