Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Establish the term "automatic member" for built-in methods and properties available on objects of any type, and create a conceptual topic for them #5627

Open
mklement0 opened this issue Mar 24, 2020 · 3 comments

Comments

@mklement0
Copy link
Contributor

@mklement0 mklement0 commented Mar 24, 2020

The engine automatically provides a number of members (methods and properties) on objects of any type: .ForEach(), .Where(), .Count / .Length, as well as indexing [<n>] (on scalars).

These are vital to PowerShell's (very useful) unified treatment of scalars and collections; a quick demonstration:

PS> $v = 42; $v.Count; $v.Length; $v[0]; $v.ForEach({ $_ + 1 })
1
1
42
43

Additionally, there are automatic members that provide reflection info: .psobject, .pstypenames, .psbase, .psextended, and psadapted.

These members are:

  • not documented as such (.ForEach() and Where() are documented as array methods, even though they're available on collections of any type and even on scalars).

  • not even programmatically discoverable via Get-Member (with the exception of the reflection-info members, which can be discovered with -Force), which is the subject of PowerShell/PowerShell#11798


I suggest:

  • establishing an official name for these members:

    • Following the pattern of automatic variable - i.e., something that is built in and automatically available - I propose automatic [type] member (which can be an automatic method, an automatic property or the automatic indexer)

    • Note: The Get-Member topic uses the term intrinsic member, but only with respect to the reflection-related members. My concern is that it's not clear what intrinsic refers to; given that intrinsic member isn't widely known, from what I can tell, whereas the concept of automatic is, namely from automatic variables, my vote is for using the term automatic member; that said, what matters at the end of the day is that we have an official term, and that that term is comprehensively documented in a single location.

  • dedicating a conceptual topic to them about_Automatic_Members - see suggestions below.


The new topic should list all the members, discuss their behavior, and note that they can be shadowed by type-native members, and can situationally be unavailable.

Notable pitfalls:

  • System.Collections.Generic.List<T> has a .ForEach() method that shadows the automatic method and behaves differently in that $_ isn't available in script blocks you pass to it, and doesn't return any value

    • ([System.Collections.Generic.List[object]] (1, 2)).ForEach({ write-verbose -vb "[$_]"; return 42 }), prints verbose message [] for each element and returns nothing.
  • IEnumerable instances such as returned by LINQ methods aren't collections per se, and calling .Count on them triggers enumeration and returns a .Count property value from each enumerated element instead (which defaults to 1).

    • [Linq.Enumerable]::Range(1,3).Count returns array 1, 1, 1 instead of 3.
  • With Set-StrictMode -Version 2 or higher in effect, accessing the .Count and .Length properties causes statement-terminating errors - see PowerShell/PowerShell#2798:

    • Set-StrictMode -Version 2; $v = 42; $v.Count fails instead of returning 1.
    • I do wish this would get fixed, however, so that automatic members are never subject to script-mode checks.
  • A type-native indexer preempts the automatic indexer - surprisingly even in cases where it only supports a non-numeric argument, such as with XmlElement

    • ([xml] '<foo><bar id="1"/></foo>').foo.bar[0].id doesn't return '1', but quietly returns $null, because indexing into scalar XmlElement .bar uses the type-native indexer that takes an element name (a string); by contrast, ([xml] '<foo><bar id="1"/><bar id="1"/></foo>').foo.bar[0].id works as expected, because .bar then returns an array.

    • See PowerShell/PowerShell#11189 for a proposal to enable the automatic indexer in case when it doesn't have to conflict with type-native indexer, due to distinct argument types.

The reflection-info members should be explained as well.

about_Properties, about_Methods, and about_Arrays should briefly introduce the relevant automatic members and also link to the new topic.

@iSazonov

This comment has been minimized.

Copy link
Contributor

@iSazonov iSazonov commented Mar 24, 2020

@SeeminglyScience

This comment has been minimized.

Copy link

@SeeminglyScience SeeminglyScience commented Mar 24, 2020

Automatic variable makes sense because other variables are manual, the user needs to set them. That distinction doesn't make as much sense (to me) for these methods, the user will almost never be constructing any other methods either. The name makes me think of events, like a method that runs automatically.

Is there a word for "intrinsic to the environment"?

@mklement0

This comment has been minimized.

Copy link
Contributor Author

@mklement0 mklement0 commented Mar 24, 2020

Is there a word for "intrinsic to the environment"?

Built-in (builtin) is the term that POSIX-like shells use for commands implemented by the shell itself, for instance; cmd.exe talks (less descriptively, to me) about internal commands.

I think built-in would have been a better name for what we call automatic variables, but that ship has sailed a long time ago.

If we conceive of automatic as "automatically available (without extra effort), always there", I think that would work for both variables and the members being discussed here.

Just like approved verbs are of necessity abstractions that aren't a perfect fit for every situation, automatic is an abstraction that I think could work in the sense described above.

Since it is safe to say that the term automatic variables won't go away, I'd rather stick with one term rather than introduce another that isn't fundamentally different.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants
You can’t perform that action at this time.