This sounds like the kind of situation where the LSP could suggest the simpler code, I'll see if there's an issue for it already and suggest it if not.
Elixir has one opinionated formatter -- Quokka -- that will rewrite the code above properly. It can also reuse linting rules as rewrite policies. Love using it.
> By accepting this
agreement and using the software you agree that Microsoft may collect, use, and disclose
the information as described in the Microsoft Privacy Statement [...]
There's a couple of terms in contract law, like fairness of obligations, unconscionability, disproportionate penalty, excessive advantage, etc. that the US seems to have forgotten. In the EU and other countries such... aberrations are struck down and unenforceable. People are still scared silly, but the ones that protest are usually left alone.
Those aspects of contract law mean that if MS included "you owe us your first born child" or "if you have not uninstalled this operating system within 2 weeks of installation, you owe Microsoft an additional one million dollars" then that clause wouldn't be valid.
They don't however mean that MS choosing to put adverts all over Windows is illegal, or a breach of the contract, just because users would prefer the OS be ad-free. The EU could legislate in various ways that would mean MS had to stop doing so, but they haven't yet and there's no aspect of general contracts law currently that prevents it.
One could argue that, and like I just wrote in my reply to your sibing comment (https://news.ycombinator.com/item?id=46087142) I would agree with you with regards to ethics, but it's not a valid argument from an actual legal perspective.
I'd love to be proven wrong about this, because I'm not blowing smoke up your ass I really do agree with you in that I wish MS could and would be sued over this, and lose, and have to stop making Windows shit like this. But I'm fairly confident that the only possibility would be for EU (or individual nations) to write new legislation addressing it.
If you bought and paid something (not a subscription) that was ad-free and then all of a sudden in a mandatory update you start to get ads, well, maybe someone already tried and failed to sue MS but personally seems pretty predatory.
From an ethical point of view I completely agree that it's predatory, I just don't believe any EU laws exist that mean anyone would have a chance of success trying to sue over that, I don't believe it to be illegal. And while I'm not all-knowing, nor am I someone who knows every single relevant law like the back of my hand, my opinion is somewhat backed up by the fact that I'm not aware of anyone with actual legal knowledge having ever suggested this behaviour of Microsoft's could be considered illegal the way you want it to be, it's only ever people who are users who think it should be considered breach of contract. (And considering how much money it would be worth if you could sue MS for this and win, if it were even a 50/50 question you'd get lawyers trying.)
You could say the same about anything, but cheating in multiplayer ruins the experience for others. Cheating in single-player? Great, we call those mods, but in a multiplayer game I'm happy to think of OP as a piece of shit for not just cheating but writing the cheats for others.
Even if it's just indirect competition, by giving yourself an advantage compared to others you affect what others percieve as a healthy benchmark for performance.
"Just neopets" isn't an excuse, you could say the same for any online game.
Cheaters even wreck just the scoreboards for some games. You might think a fake score submissions is about the least damaging thing since it doesn't directly effect others gameplay at all, but it still ruins the experience and affects the community's ability to compare and share genuine runs.
Being banned eventually is hardly a punishment, doubly so if they ever sold-on their ill-gotten gains for real money.
There wasn't a hint of contrition in OP's post, and the downvotes I'm receiving suggests that the culture of entitlement is so great now that cheating in multiplayer isn't even seen as bad anymore.
I hope you share that same energy for people doing high frequency trading or writing advertisement engines. Cheating in neopets is probably at the lowest end of harm caused by cheating and also hurts neopets devs more than it hurts other players.
I think it's reading into a lot into OPs comment. A lot of people look somewhat fondly on dumb/slightly illegal things they did as a teen, even if they would never do such a thing as an adult (nor encourage it in current teens). The downvotes you are getting are likely due to guidelines violations (be kind, curious, not snarky, etc) not due to your actual viewpoint.
Also I went through SPy's repo, and also looked at what they beat us in, we have advantages in certain areas. But so do they, so i've already planned new features to make our language even more powerful!
Here's my take. It helps you enforce properties about your data. Didn't mean to make this response so long, but alas.
(*
Quick note on notation: I will use "double quotes" when referring to _values_ and `backticks` when referring to _types_.
*)
(*
Think of this as an interface. It defines the shape of a module. Notice that the interface describes a module that defines a type called `t`, and two values: "of_string", and "to_string", and they are functions with types: `string -> t`, and `t -> string`.
*)
module type ID = sig
type t
val of_string : string -> t
val to_string : t -> string
end
(*
Below this comment is a module named "Id" that _is of type_ (in other words: it _implements the interface called_) `ID`. Due to the explicit type annotation (Id : ID), now from the perspective of anywhere else in the code, the exported interface of the module "Id" is `ID`.
Modules only contain two things: `type declarations`, and "values". Values are your primitives such as 1, '<', "hello", but also composite such as (fun x -> x + 1), (Some x), f x, { foo = "bar"; baz = 42 }, and even (module Id) (yes! modules can be values too!). Type declarations tell the compiler . Anything which is a value _always_ has a type that can _usually_ be inferred.
No type annotation is necessary when the compiler correctly deduces the type of your value through static analysis. For instance, in the module below, "of_string" is deduced to be of type ('a -> 'a). The ' on the symbol 'a signifies a "type variable", and it means that it can be filled in with any type. For instance (t -> t) and (string -> string), but not (t -> string) or (string -> t). For those it would have to be of type ('a -> 'b). We cannot deduce this type, however, because our implementations do nothing with their inputs besides return them. Since nothing is changed, it's always the same type.
Now, can you spot the pink elephant? Notice how the "ID" interface from above defines "of_string" to be of type (string -> t). How can this be possible? It's because we gave the compiler a hint when we said `type t = string`. This says that a "value" of type `t` is backed by a value of type `string`. If something type checks as `t`, it also type checks as `string`.
So, we could reason through and say ('a -> 'a) can be instantiated to (t -> t), but `t` is also equal to `string`, so we can mentally imagine a hypothetical intermediate type... something like ({t,string} -> {t,string}). This type and type equality is visible _inside_ the module. But when the `ID` interface was applied over the `Id` module as in (Id : ID), this has the effect of hiding the type equality (the fact that `type t = string`) because in the `ID` interface we define `t` without an equals sign: `type t`. This forces us to _choose_ a concrete type to expose externally, even though the type is less general than what the implementation sees.
NOTE: OCaml doesn't use parens for function definition or application. Compare this OCaml code against its Python equivalent.
> let hello_world h w = (h, w)
> let h, w = hello_world 1 2
vs.
> def hello_world(h, w):
> return (h, w)
> h, w = hello_world(1, 2)
*)
module Id : ID = struct
type t = string
let of_string s = s
let to_string s = s
end
let main () =
let s = "abc123" in
let id = Id.of_string s in
(* NOTE(type error): because the built-in "print_endline" function is of type (string -> unit) and not (Id.t -> unit) *)
(* NOTE: if an expression returns unit, you don't need to create a let binding for it. You can simply tack a semicolon to the end of it if you need sequence another expression to follow it. *)
print_endline id;
(* okay *)
(* STDOUT: abc123 *)
print_endline (Id.to_string id)
;;
main ()
You could imagine implementing this pattern of defining parsers such as "of_string", "of_bytes", "of_json", "of_int", "of_db_row", "of_request", for any piece of input data. You can think of all of these functions as static constructors in OOP... you take in some data, and produce some output value: e.g. "of_string" takes in a `string` and produces a `t`.
Now, if you have a bunch of "values" of type `t`, you know that they _only_ could have been produced by the `of_string` function, because `of_string` might be the _only_ function that ends with `-> t`. Therefore, all the values maintain the same properties enforced by the `of_string` function (similar to class constructors in OOP). With this, you can create types such as `Nonnegative.t`, `Percent.t`, `Currency.t`, `Image.t`, `ProfilePicture.t`, and parsers from another type to the newly minted type.
The compiler can help you enforce these properties by providing guardrails in the form of static compiler checks (these checks are run _before_ your code can even be compiled). If I have a value of type `Nonnegative.t`, then not only do I not need to validate that it's not negative, I also don't have to validate that it's not negative everywhere else that values of that type are used -- the validation logic is baked into the constructor. Parse, don't validate.*
A language can be suitable for writing a compiler, but if there is another language that's 10x faster that's also suitable, then you're losing out on a lot of compilation speed for no reason.
Dog-fooding a language by writing a compiler in it can lead to the designers adding language features to make compiler development easier, even if they detract from the design of the language for the 99% of users who aren't writing a compiler.
reply