Welcome to the Onshape forum! Ask questions and join in the discussions about everything Onshape.

First time visiting? Here are some places to start:
  1. Looking for a certain topic? Check out the categories filter or use Search (upper right).
  2. Need support? Ask a question to our Community Support category.
  3. Please submit support tickets for bugs but you can request improvements in the Product Feedback category.
  4. 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_kingeryjacob_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?


  • kevin_o_toole_1kevin_o_toole_1 Onshape Employees, Developers, HDM Posts: 551
    Well, the flip side of that you might have expressions like "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?
  • jacob_kingeryjacob_kingery Member Posts: 39 EDU
    To check my understanding, are each of the following correct?
    (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 around 1 + 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 that skRectangle, for example, is auto-populated with a string ("rectangle1") as its id, but other functions such as newSketch don't allow strings for the id argument. Is there a reason for this difference?
  • kevin_o_toole_1kevin_o_toole_1 Onshape Employees, Developers, HDM Posts: 551
    edited October 2015
    On your first question, those are all correct. Note that 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.

    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.

  • jacob_kingeryjacob_kingery Member Posts: 39 EDU
    Is there documentation somewhere about ids (context.fs?)?  I guess I had assumed that ids were basically strings with some kind of designation about the required uniqueness, but I'm getting the feeling that this is not the case given some of the terms you've thrown out here (hierarchy, tree-like, sub-id, leaf).  I think ids could be a major point of confusion, especially if something being called an id (like in a sketch) is not actually an <keyword>id</keyword>.

    id + "string" + 1 seems reasonable, though it feels a little weird to see "string" + number in there since alone it generates a Non-numeric operand warning.
  • kevin_o_toole_1kevin_o_toole_1 Onshape Employees, Developers, HDM Posts: 551
    edited October 2015
    An Id is an array of strings, where the first string represents the broadest group of operations and each successive string represents a more specific group. A full id can point to (at most) a single operation. You can think of Ids like operation-filled folders.

    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 parameter id. Any errors reported (via  reportFeatureError(...)) on ids starting with  "FOmyDjQ6suhvqw1_1" will be associated with the "FOmyDjQ6suhvqw1_1"&nbsp;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, calling qCreatedBy("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 as  Id + row + column, rather than  Id + running_index to make the feature more robust to grid resizing. 

Sign In or Register to comment.