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

Type.Is Nullable Type Rule Clarification #200

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion query-languages/m/type-is.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ Type.Is(<b>type1</b> as type, <b>type2</b> as type) as logical

## About

Determines if a value of `type1` is always compatible with `type2`.
Determines if a value of `type1` is always compatible with `type2`.

Parameter `type2` is expected to be a nullable primitive type. When this requirement is not met, this function's behavior is undefined and so should not be relied on.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not true. By passing a nullable primitive type as the second arg, you can use Type.Is to check for both the nullable and non-nullable version of that type. But that's just one use of the function.

Here's another way it can be used, which doesn't involve nullable types at all:
Type.Is(Int64.Type, type number)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @ehrenMSFT,

Thanks for this feedback.

Here's another way it can be used, which doesn't involve nullable types at all:
Type.Is(Int64.Type, type number)

I'm puzzled. Isn't type number a nullable primitive type (where nullable primitive type = all primitive types + their nullable counterparts)?

In the language spec, operators as and is are described as only accepting "nullable primitive types as their right operand," and Value.Is's second argument is described as accepting "an arbitrary type value as its first and a nullable primitive type value as its second argument." Examples are given like Type.Is(type number, type text) and 1 is number.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about the spec. I'm just basing my comments on how things actually seem to work.

Type.IsNullable(type number) returns false. You'd have to say "type nullable number" to make it nullable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @ehrenMSFT!

Just opened a PR raising the question of how to best address the "nullable primitive type" terminology used in the spec.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ehrenMSFT, just edited this to reflect the terminology that #203 has moved to. Does this look good to you now?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where are you getting the limitation that the second type must be a primitive or nullable primitive type? I don't see any limitation like this in our code. The logic seems more involved than that.

For example, the following returns true, even though Int64.Type isn't a primitive type.

Type.Is(type number, Int64.Type)

To give other examples, this returns false:
Type.Is(type [a=number], type [a=number])

while this returns true:
let recordType = type [a=number] in Type.Is(recordType, recordType)

How does the info you added account for these examples?

Copy link
Contributor Author

@bgribaudo bgribaudo Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @ehrenMSFT!

Happy New Year!

Where are you getting the limitation that the second type must be a primitive or nullable primitive type? I don't see any limitation like this in our code. The logic seems more involved than that.

The spec mentions this limitation—https://learn.microsoft.com/en-us/powerquery-m/m-spec-types:

Compatibility between a given type and a nullable primitive type can be determined using the library function Type.Is, which accepts an arbitrary type value as its first and a nullable primitive type value as its second argument: [...] There is no support in M for determining compatibility of a given type with a custom type.

I'd assumed that the above quote from the spec is correct, and so assumed that if Type.Is seems to work when its second argument is not a primitive type or a nullable primitive type, its behavior shouldn't be relied on.

If that is inaccurate, can you advise on what is allowed as the second argument? Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, thanks for clarifying I think I understand now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you planning to also update m-spec-types to mention that both nullable and non-nullable primitive types are supported?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


## Example 1

Expand Down