Welcome to the Onshape forum! Ask questions and join in the discussions about everything Onshape.
First time visiting? Here are some places to start:- Looking for a certain topic? Check out the categories filter or use Search (upper right).
- Need support? Ask a question to our Community Support category.
- Please submit support tickets for bugs but you can request improvements in the Product Feedback category.
- Be respectful, on topic and if you see a problem, Flag it.
If you would like to contact our Community Manager personally, feel free to send a private message or an email.
id + "string" ~ number
jacob_kingery
Member Posts: 39 EDU
Something we ran into that confused us for a while was creating unique ids with a string and a number like in the title. This does not work as written. Printing this results in something like 'Id(11): [ "FOmyDjQ6suhvqw1_1" , "patternSketch" ]0'. What did work for us was adding parentheses -- 'id + ("string" ~ number)' -- which results in '[ FOmyDjQ6suhvqw1_1 , patternSketch0 ]'. It seems intuitive that the original way did not work; is this a bug or an intended behavior?
0
Comments
"I have " ~ 1 + 3 ~ " sandwiches"
, where ~ deserves lower precedence.Yours is admittedly a more realistic FS use case, but keep in mind that the ~ operator will stringify just about everything, and it's probably more annoying (and harder to diagnose) if your variables are being unexpectedly cast to strings.
If we're going to change something as fundamental as operator precedence, it definitely has to be now, so we'll discuss this more on Monday.
Independently, would having the autocomplete be
id + ("string")
be helpful, or just confusing?(id + string) is Id
(string ~ number) is string
(id ~ number) is string
(id + number) is Id
In your
"I have " ~ 1 + 3 ~ " sandwiches"
example, I personally would almost certainly put parentheses around1 + 3
to remove ambiguity, which seems to imply that my mind is prioritizing+
and~
on the same level, for what it's worth.I think putting
id + ("string")
might be more confusing than helpful. Would it be possible to have a special case for the~
operator such that(id ~ number) is Id
? Something else I noticed is thatskRectangle
, for example, is auto-populated with a string ("rectangle1"
) as its id, but other functions such asnewSketch
don't allow strings for the id argument. Is there a reason for this difference?Id + number
converts the number to a string and adds a new sub-id (rather than appending the number to the last leaf). The addition implementations for Ids are in context.fs, while ~ is defined in the language itself: it's behavior is always to concatenate the two operands after converting them to strings.On your last question: The difference is that sketch ids are not hierarchical, while feature ids are. The newSketch function is creating a feature (i.e. something which, in standard modeling, appears in your feature tree). Thus, its id can be a child of any other feature. The skRectangle function only creates things internal to the sketch, where the hierarchy is flat. Thus, sketch ids are just unique strings, not full Ids.
On Ids in general, there's definitely things that are harder to do that we'd like, and errors related to Ids are harder to diagnose than we'd like. The fundamental reason an explicit Id is necessary in every operation is that it makes downstream designs robust to upstream changes. For instance, if I have an function/feature that makes three features, but the Feature2 is optional, I want Feature3 to have the same Id regardless of whether the second feature got made. Why? Well, it means that a feature relying on the geometry from Feature3 downstream won't break when you change Feature2. Related: the fundamental reason Ids are tree-like instead of in a flat hierarchy is so that parent features can report errors from their children, and so that you can find child geometry through parent features.
Anyway...
After discussing this with Lana, the easiest and clearest thing to standardize on is probably
id + "string" + 1
. There's really no downside or different behavior, and it can give you a bit more flexibility when using e.g.qCreatedBy
later on.id + "string" + 1
seems reasonable, though it feels a little weird to see"string" + number
in there since alone it generates aNon-numeric operand
warning.For instance, you gave the example of the Id
[ "FOmyDjQ6suhvqw1_1" , "patternSketch" ]
. The first string in the list,"FOmyDjQ6suhvqw1_1"
is the Id of the main feature (the one you added in the part studio). That string is autogenerated, and passed into the feature function as the parameterid
. Any errors reported (viareportFeatureError(...)
) on ids starting with"FOmyDjQ6suhvqw1_1"
will be associated with the"FOmyDjQ6suhvqw1_1"
feature. This will make the feature red in your feature tree, and report an error in the hover-text. Errors thrown inside your feature function will have the same behavior. Additionally, callingqCreatedBy("FOmyDjQ6suhvqw1_1")
will return any entities created by an operation using an id starting with"FOmyDjQ6suhvqw1_1"
. Other Id-based queries behave the same way.We call an id prefix (representing a group of operations) a parent id, and we call specific ids with that prefix sub-ids, or perhaps child ids. We say ids are tree-like because the set of all ids, with children connected to their parents, forms a tree.
The + operator is overloaded for Id + string, Id + number, and Id + Id so that the string, number, or list of strings will be appended to the array of strings as new, individual strings. This simply provides a convenient way to make child ids from parent ids.
If you want to give every feature in your document an id of the form
Id + "unique string"
, that's fine. However, you may find it useful to group them into sub-ids for the sake of making nicer queries. It is generally a bad idea to keep a running idCount referring to multiple, independent portions of your features. This is because geometry created by those ids will need to be referenced downstream, and you want that geometry to persist whenever independent things about your upstream feature have changed. Thus, a parent id is nice to have for grouping independent sections. Additionally, a grid of objects is best labeled asId + row + column
, rather thanId + running_index
to make the feature more robust to grid resizing.