4 ms·
Did you read the article? The correct way of doing Hungarian Notation, as demonstrated in this article, is to encode in the name of the variable what it does,
by hota_mazi 7y ago
Did you read the article?
The correct way of doing Hungarian Notation, as demonstrated in this article, is to encode in the name of the variable what it does, not its type.
No compiler can know that a string variable is a "name" or a "password".
- lifthrasiir 7y agoIt still might be possible to have types like `UserId` or `UserCredential`, which get parsed at the request time and never roll back to plain strings. It is evident that they are indeed different subtypes of strings: user identifiers can't have a space for example. That said, I generally agree that conventional type systems are not (yet) capable of encoding all those informations to a type. I prefer a mix of actual types and coding conventions for the practical matter.
- usrusr 7y agoAs a thought experiment, I like to assume that there is a hypothetical language where everything is encoded in types, to the point where you don't have or need variable names anymore. Every typed language (and programming style) we use is some point in the spectrum of practical compromises between that hypothetical language where all pre-runtime information is in formal types and scripting languages where all pre-runtime information is in informal names. Java for example has to leave quite a lot of that information in names because there are no type aliases and final types exist.
- touisteur 7y agoI'm curious what type of capabilities are lacking in the Ada or the F# type system to handle this. You can create 'new' (hear incompatible) types instead of subtypes and they won't be affectable to each other. So type User_Id_Type is new String; type User_Credential_Type is new String; Then in your request deserializer convert once from String to the correct type, and at the use site only allow taking the correct type? You can also add static predicates to ensure User_Id_Type doesn't contain spaces. You can also make the type 'opaque' and it won't be possible to convert to a String without a bespoke interface. I'm not sure what's missing. I almost feel like it would be a great challenge :-)
- lifthrasiir 7y agoI think in this particular case they suffice, because they are clearly different subtypes as I've mentioned. It is much harder, if not impossible, if you have to describe a relation between two or more values of the same subtypes. For example, imagine that you already "know" certain indices never go off the boundary of given array but want to encode that information to types. Sure, there exists a Rust crate [1] that tracks a relation between indices and originating array via lifetime, but it is complicated. [1] https://github.com/bluss/indexing https://github.com/bluss/indexing
- touisteur 7y agoMmmh thanks for the link and the paper about generative types. Seems very interesting! I'm wondering if using type predicates or type invariants (+ proof for static verification, otherwise the check will mostly be at runtime) would help here. Look up https://blog.adacore.com/spark-2014-rationale-type-predicates https://blog.adacore.com/spark-2014-rationale-type-predicate... if interested.
- dragonwriter 7y ago> No compiler can know that a string variable is a "name" or a "password". In pretty much any language supporting user-defined types and/or type aliases, types can be used for that information (with aliases, providing documentation the same as hungarian notation does; with real types, providing the possibility for enforced protection against accidental misuse.) But the article doesn't actually use hungarian notation for that kind of thing, it uses it for traits that are not "what it does", but instead metadata analogous to Ruby's "taint". Which, again, is something easily encoded in typing, in a static language, either as a core feature of typing or via user-defined (possibly wrapper, depending on other features of the type system or general language semantics) types; type aliases, even, would work as well as hungarian notation, but using actual types lets you put guarantees in place rather than just providing documentation.
- jchw 7y agoHungarian notation solves one problem: it makes wrong code look wrong. Type alias can also do that, but they can do so in a way where correctness can be statically enforced. As an example, let’s say you have a Write function like in the article, but it only takes an HTMLString, which can’t implicitly be casted from String. Then, you can have Encode return an HTMLString, but take a String. Finally, you can use static analysis to only allow whitelisted functions to construct non-literal HTMLStrings (so anyone could do a literal of HTML, but every other usage would require encoding or whitelisting.) This is a bit rudimentary of an example, but it is widely used in practice. Here is a safe type used in Closure: https://google.github.io/closure-library/api/goog.html.SafeHtml.html https://google.github.io/closure-library/api/goog.html.SafeH...
- eloisant 7y agoActually it can, you just have to define types for it. In Scala you have value class, that get replaced by the underlying type during compilation so there is no overhead. https://ivanyu.me/blog/2014/12/14/value-classes-in-scala/ https://ivanyu.me/blog/2014/12/14/value-classes-in-scala/ It may sounds a hassle but you only have to handle it at the interfaces (for example for a web app in the controller and data layer), in the rest of the code you just manipulate your value like any other type.
- Mikhail_Edoshin 7y agoBut type is a machine-readable way to say what a variable does or is. A compiler can certainly know a name from a password if its type support is versatile enough and you use separate types for them. Or, for example, for things like "unchecked C string", "valid UTF-8 C string", "NKFD-normalized UTF-8 C string", etc. A separate type for password may be a jolly good idea with a logging system you can dump any data to; you certainly wouldn't want it to log passwords. Using prefixes is a poor man's type system, a loose convention to be enforced by humans, while with types it would be a machine-readable and enforceable requirement.
- marcus_holmes 7y agoIn Go: type Password string type Name string func SayHello(name Name) { fmt.Println("Hello %s",string(name)) } func Login(password Password) bool { if bcrypt.magicstuff([]byte(password)){ return true } log.Println("error: wrong password: ", string(password)) return false } Now the type system does know whether it's a name or a password, and will throw a compiler error if you try to use the wrong one in the wrong place. edit: really HN, no code formatting options? :(