Engine APIs can return false-y values and do not error when passed values whose types can never return non-nil.
Examples:
local str = "Hello, World!"
print(str.Name) -- returns 'nil'. Should error out: 'attempted to index 'Name' of string'
local Workspace = game:GetService("Workspace")
local t = {}
print(Workspace:FindFirstChild(t)) -- returns 'nil'. Should error out: 'attempted to pass 'table'; expected string
The specificity of the error messages are semantic and shouldn’t be considered exactly what I expect. My point is that they should error. If they do not, what is presented is a very confusing DX; not everyone uses exact type safety, and nor can Luau’s inference engine provide that.
Expected behavior
Until inference is bulletproof, intra-engine assertions should not be removed, to spare developers’ time in debugging issues of type safety. Type inference does not always co-exist with type safety.
Regardless of __namecall back-compatibility, attempting to reference members of the string type should still error out if the member doesn’t exist as a method of all strings.
The string type in Lua actually has a metatable attached by default to allow namecall methods such as :format. Because of this, indexing from it returns nil instead of throwing (try print(("").a))
Userdata arguments get auto-coerced into a string just like with tostring. What’s happening here is its converting t into "table: 0x0" and not finding anything.
Although engine assertions are quite nice, they incur a significant performance penalty even for perfectly legal code. Especially with native codegen, it would be better if strictly typed scripts were given less runtime checking due to it being already proven as valid.
I’m unsure of your understanding. __namecall-ing a non-existent member of the string library errored in the past. It was made to not error now, games then became reliant on it not erroring … and now the opposite behavior is considered compliant and backwards compatible.
It’s backwards to your understanding . And whether it’s viable for backwards compatibility, I still think the logic is generally incorrect.
Further, what’s the explanation for being able to FindFirstChild a table? number? any non-string data type?
EDIT: I shouldn’t phrase this as a “my opinion is” argument. The prior behavior was fine. A regression was made, worse DX and objectively worse logic was introduced and will plague everyone over time. I don’t want confusing behavior in my work
Engine APIs accepting invalid types is nothing new. It’s been like that for as long as I can remember.
Your understanding of string indexing is probably correct (it used to error, now it doesn’t) but now that it doesn’t error, it is actually a compatibility concern to make it error. I know that’s frustrating and after talking to people on the Luau team I know they wish they could change it, but they can’t.
You should look into using typed Luau since it’ll help avoid these issues.
Lua and by extension Luau is designed to take numbers in all APIs expecting strings. With so many experiences build on top of that, it’s not something you start blocking and expect things to work out.
We will try to block all other types though, but if we still have many players in that one experience that calls part:IsA(part) to get always get true for some reason, it will be a problem.
string indexing will remain unchanged, use Luau --!strict and type annotations to catch issues earlier
passing non-string arguments to string parameters in engine APIs might output a warning message in the future, use Luau --!strict to catch more issues before code is even running
Workspace:FindFirstChild({}) should now report a warning to Studio Output.
In a similar way, any non-string value passed to an engine API where string is required will issue a warning.
And also, doing something like workspace:FindFirstChild(1) still gives the warning, even if an instance named “1” exists in workspace (it does get returned though)