It means that you paying taxes on your pay is equivalent to your employer paying taxes on your pay. If you shift taxes to the employer, then they will reduce your pay accordingly.
Never ever once has an employer given me a pay raise when they got a tax cut or a pay cut when they got a tax hike.
Taxes do not feature into salary negotiation. Employers pay as little as they can get away with, while employees want to get as much money as they can.
If you need theoretical worlds with no correspondence to anything ever in actual history to justify your claim, then maybe there is not that much to it.
The point is valid based on the context here, but taxes certainly feature in compensation.
Notably if you’re considering moving from a no/low tax locale to a higher one.
Two spectacular examples are the MLB contracts of Shohei Ohtani and Vladimir Guerrero.
Ohtani is getting paid very little ($2M/year) for his 10 years with the Dodgers, the vast majority is deferred to when after he leaves the team (and, notably, probably) California (likely back to Japan).
Vlad’s large contract is padded with a very large (like $175M I think) “signing bonus” to be paid over 10 years. The key point is that money will be earned “where he lives “, which is Florida, not where he plays (Toronto).
Both of these are structured to avoid local (high) tax jurisdictions.
But not just superstar athletes need to consider this. Anyone moving for work to a higher tax locale needs to consider that during salary negotiations.
Social Security and Medicare (FICA) is not exactly a tax, if that is what you are talking about. There is FUTA (Federal Unemployment Tax) paid by employers, but this is quite low, certainly not a significant portion of tax revenue.
The IRS calls it a tax. In what sense is it not exactly a tax? It’s a mandatory payment to the government. It functions like a tax and it’s called a tax.
This statement is just not factual without some qualification. Where I live, and in the US in general, tipping is not a thing of the past. You can say you wish it was, you can say it should be, but what you said is not factual.
I wonder if they will approve my new apps: “Ezzy” and “Cray” where people can rate dates for how easy it was to get them into bed and how crazy they were during and/or after.
I'm somewhat opposed to the idea of having a walled garden App Store as Apple does, which is why I don't use Apple.
But Apple insists they do have a walled garden, and people buy Apple with that expectation, so I certainly hope and expect that Apple doesn't approve apps like these. Any app that does doxxing as a service should not be on Apple's app store IMO.
If you hate humans so much that you want to leave the planet you maybe need help from a professional, though to be frank most mental health professionals will probably make it worse.
From what I have seen about this it's all tied up with academic research projects, and if there is one group of people with absolutely no sense for engineering, it's modern academics. They seem to not get that software that can be used for some commercial application (i.e. something that serves some actual user) is much more important than software that can pad your resume.
Is it? Certainly hasn't been the experience of my two autistic daughters who had years of difficulty and which led to real problems for a decade or so each during later later schooling and early work years. Both are now doing much better but it's been a long uphill battle for them. The same of my two sons but society is much more tolerant (but bit fully) off their symptoms as they tend to be viewed as 'male' tendencies, just severely amplified.
I have taken boatloads of psychedelics in my life. If I could do my life over again I would have traded every single trip for having read Orthodoxy and the Everlasting Man by Chesterton before I was 25. Tripping gives you zero insights into the divine, it is not revelation, you don't get closer to God. There are real answers, but we as civilization have been deliberately moving away from under false premises, and the world has gotten worse and worse. Drugs can't fix this. If you want a better world, you should not dull your perception of it.
Something that would be much more beneficial for all humanity is if more of the clergy actually preached the bible, instead of trying to explain it away, which is almost exclusively what the clergy I have engaged with tries to do.
I take this book was life changing to you, would you mind explaining a bit more on why? If you read it before 25, do you think it would have the same effect, given your different experience at that age?
Psychedelics caused me to isolate from society and those around me. It makes you feel more connected while actually becoming less connected, it makes you feel that you understand while actually understanding less.
I see now that the real pleasure in life is in being connected with your local community, with those around you — not because you agree with them, not because they think or look the same as you, but because they are yours, and you are theirs in a very deep sense.
I also see now that the Church of Christ makes this possible, it's a vehicle for fulfilling our purpose in life. No other thing exists which provides the same avenue, nothing else even comes close.
The specific changes the books made in my life is that it helped me get over my superficial objections to Christ (I was an atheist from the age of about 14), it helped me see the whole, and thus helped me adopt Christ as my saviour, and the Church as my Church, and it brought me to a point where I have faith without doubt.
> We know better than the scholars, even those of us who are no scholars, what was in that hollow cry that went forth over the dead Adonis and why the Great Mother had a daughter wedded to death. We have entered more deeply than they into the Eleusinian Mysteries and have passed a higher grade, where gate within gate guarded the wisdom of Orpheus. We know the meaning of all the myths. We know the last secret revealed to the perfect initiate. And it is not the voice of a priest or a prophet saying, ‘These things are.’ It is the voice of a dreamer and an idealist crying, ‘Why cannot these things be?’
Given current major religions are visibly inventions of men to cover basic existential fears we all face and were done during roughly iron age era with corresponding illogical parts and conflicting statements, no amount of drugs are going to move any normal person to whatever god or God represents in this universe.
The introspection part is where true gold is - and to be honest that tells a lot about where we feel above topic is in our cores (and as you yourself confirmed from your experiences, like it or not).
More religion and preaching got us medieval dark ages and tons of endless wars and genocide, I think mankind deserve a bit more these days.
Go's quite horrendous and limited type system makes it a poor fit for everything. The worst thing about Go is, in fact, the language. Everything except the language redeems it.
I have been programming in Go for several years now and I agree, though I am not that sure even the rest of the ecosystem redeems it that much.
On the other hand, the programming languages used by LLM people seem to be python and javascript mainly.
So while I argue that they all should really move on to modern languages, I think go is still better than the I-can't-even-install-this mess of python and javascript imports without even a Dockerfile that seem to be so prevalent in LLM projects.
If you want to know only about the type system, nowadays it's mostly the lack of basic enums, a clear divide in basic features of the language and of the libraries (and modern generics support) leading to things like `len(..)` vs `.Len()`. Those actually end up playing a bigger role than it seems imho, but even just the rest is death by a thousand cuts.
You can find many articles on the internet about it, but in my experience I would summarize it in:
It looks like it's made to have a simple compiler, not to simplify the programmer's life.
Initially its simplicity is wonderful. Then you start to notice how verbose things are. Channels are another looks-nice-but-maybe-don't feature. nil vs nil-interface. Lack of proper enums is hurting so much I can't describe it. I personally hate automatic type conversions, and there are so many inconsistencies in the standard and most used libraries that you really start to wonder why some things where even done. validators that validate nothing, half-done tagging systems for structs, tons of similar-but-not-quite interfaces and methods.
It's like the language has learning wheels that you can't shake off or work around. You end up wanting to leave for a better one.
People had to beg for years for basic generics and small features. If google is not interested in it, you'd better not be interested in it and it shows after a while.
Companies started to use it as an alternative to C and C++, while in reality it's an alternative to python. Just like in python a lot of the work and warnings are tied into the linter as a clear workaround. Our linter config has something like 70+ linters classes enabled, and we are a very small team.
C can be described as a relatively simple language (with caveats), C++ has grown to a blob that does and has everything, and while they have lots of footguns I did not find the same level of frustration as with go. You always end up fighting a lot of corner cases everywhere.
Wanted to say even more, but I think I ranted enough.
> Lack of proper enums is hurting so much I can't describe it.
Do you mean sum types? That is not a case of them not being "proper", though. They simply do not exist as a feature at all.
Go's enums function pretty much like enums in every single other language under the sun. If anything, Go enums are more advanced than most languages, allowing things like bit shifts. But at the heart of it all, it's all just the same. Here are enum implementations in both Go and Rust:
While Go leans on the enum value produced by `range` to act as the language's enumerator, while Rust performs explicit incrementing to produce the enumerator, the outcome is no different — effectively nothing more than [n=0, n++]. Which stands to reason as that's literally, as echoed by the dictionary, what an enum is.
Go doesn't even classic type-safe integer-value enums like in C++ or enums.
Yes, you can emulate this style of enums by using iota to start a self-incrementing list of integer constants. But that's not what any language (except for C) has ever meant by "enum".
Enums are generally assumed to be type-safe and namespaced. But in Go, they are neither:
type Color int
const (
Red Color = iota
Green
Blue
)
func show(color Color) {
fmt.Printf("State: %v", color)
}
fun main() {
show(Red)
show(6)
}
There is no namespacing, no way to — well — enumerate all the members of the enum, no way to convert the enum value to or from a string (without code-genreation tools like stringer), and the worst "feature" of all is that enums are just integers that can freely receive incorrect values.
If you want to admire a cool hack that you can show off to your friends, then yeah, iota is a pretty neat trick. But as a language feature it's just a ugly and awkward footgun. Being able to auto-increment powers of two is a very small consolation prize for all of that (and something you can easily achieve in Rust anyway with any[1] number[2] of crates[3]).
> Go doesn't even classic type-safe integer-value enums like in C++ or enums.
Sure, but now you're getting into the topic of types. Enums produce values. Besides, Go isn't really even intended to be a statically-typed language in the first place. It was explicitly told when it was released that they wanted it to be like a dynamically-typed language, but with statically-typed performance.
If you want to have an honest conversation, what other dynamically-typed languages support type-safe "enums"?
> But that's not what any language (except for C) has ever meant by "enum".
Except all the others. Why would a enum when used when looping over an array have a completely different definition? It wouldn't, of course. Enums are called what they are in a language because they actually use enums in the implementation, as highlighted in both the Go and Rust codebases above.
Many languages couple enums with sum types to greater effect, but certainly not all. C is one, but even Typescript, arguably the most type-intensive language in common use, also went with "raw" enums like Go.
It's not about 'range', and like you said enum and sum types are tied concepts in other languages, and yes I was talking about sum types.
Even without sum types, there is a common pattern of defining a new type and const-defining the possible values that is a clear workaround on the lack of an 'enum' keyword.
Maybe because the compiler can't be sure that those const values are all the possible values of the type, we can't have things like enforcing exhaustive switches on this "enum", and that is left to the linter at best.
Default-zero initialization is always valid too, which can leave you with an "enum" value that is not present in the const definitions (not everything starts on iota, iota does not mean 0).
It's a hack, it became a pattern. It still is not a proper (or even basic) enum even without sum types.
It is to the extent that it helps explain what an enum is, and why we call the language feature what we do. Python makes this even more apparent as you explicitly have to call out that you want the enum instead of it always being there like in Go:
for i, v in enumerate(array):
# ...
In case I'm not being clear, an array enumerator like in the above code is not the same as a language enumerator, but an array enumerator (or something similar in concept) is how language enumerators are implemented. That is why language enumerators got the name they did.
> It still is not a proper (or even basic) enum even without sum types.
It most certainly is "proper". In fact, you could argue that most other languages are the ones that are lacking. Go's enums support things like bit shifts, which is unusual in other languages. Perhaps it is those other languages that aren't "proper"?
But, to be sure, it's not sum types. That is certain. If you want sum types you are going to have to look elsewhere. Go made it quite clear from the beginning that it wanted to be a "dynamically-typed language with statically-typed performance", accepting minimal static type capability in order to support the performance need.
There is definitely a place for languages with more advanced type systems, but there are already plenty of them! Many considerably older than Go. Haskell has decades on Go. Go was decidedly created to fill in the niche of "Python, but faster", which wasn't well served at the time. Creating another Haskell would have been silly and pointless; but another addition to the long list of obscure languages serving no purpose.
> Companies started to use it as an alternative to C and C++, while in reality it's an alternative to python. Just like in python a lot of the work and warnings are tied into the linter as a clear workaround. Our linter config has something like 70+ linters classes enabled, and we are a very small team.
I thought the main "let's migrate our codebase to Go" crowd had always been from the Java folks, especially the enterprise ones. Any C/C++ code that is performant is about to get a hit, albeit small, from migrating to a GC-based runtime like Go, so I'd think that could be a put off for any critical realtime stuff - where Rust can be a much better target. And, true for both C++ and Java codebases, they also might have to undergo (sic) a major redux at the type/class level.
But yes, the Googlers behind Go were frustrated by C++ compile times, tooling warts, the 0x standard proposal and concurrency control issues - and that was primal for them, as they wanted to write network-server software that was tidy and fast [1]. Java was a secondary (but important) huge beast they wanted to tackle internally, IIRC. Java was then the primary language Googlers were using on the server... Today apparently most of their cloud stuff is written in Go.
Well, there's a difference between "our program is written in C++ because we correctly chose it for its performance" and "our program happens to be written in C++ because some programmer 10 years ago really liked C++".
There's a lot of software out there that either was written before good modern options existed, or uses very outdated patterns, or its language wasn't chosen with much thought.
I think the point was that "Go's quite horrendous and limited type system" gets in the way of everything (programming in general), nothing specific to crafting agents.
There's a lot of discussions on the internet about the bad design decisions of Golang (for example around channels, enums, error handling, redeclarations, interfaces, zero values, nilability... at least generics aren't so much a subject anymore)
To be fair, it is unlikely that Go would have a static type system at all if they had figured out how to achieve the performance expectations without. It was made abundantly clear that it is intended to be like a dynamically-typed language, but faster. Thinking of it as being a statically-typed language is a bit flawed, and shows a gross misunderstanding of what the language was created for.
While you could try to argue that dynamically-typed languages in general are a poor fit for everything, the reality is that people there are typically using Python instead – and the best alternative suggestions beyond Go are Erlang and Elixer, which are also dynamically typed, so that idea doesn't work. Dynamic typing is what clearly fits the problem domain.
I agree- multiple return values don't compose; errors are better than exceptions, but still super verbose; channels have a lot of foot guns; enums are just sad.
But despite all of that the language has some really good qualities too- interfaces works far better than it feels like they should; the packaging fits together really well (I'm learning Rust right now and the file structure is far more complicated); and people are able to write a lot of linters/codegen tools BECAUSE the language is so simple.
All in all I worry the least about the long term maintenance cost of my Go code, especially compared to my Python or JS code.
There isn't much more you can do with them. Literally all an enum can produce is a number.
In increasingly common use in a number of languages, enums are being coupled with discriminated unions, using the enum value as the discriminant. This is probably what you're really thinking of, noticing Go's lack of unions.
But where you might use a discriminated union if it were available, you would currently use an interface, where the type name, rather than an enum, is what differentiates the different types. If Go were to gain something like a discriminated union, it is likely it would want to extend upon that idea. Most especially given that generics already introduced syntax that would lend itself fairly well to it:
type Foo interface {
Bar | Baz
}
Where enums are used to act as a discriminant in other languages, that is largely just an implementation detail that nobody really cares about. In fact, since you mentioned Rust, there are only 8,000 results on Github for `std::mem::discriminant` in Rust code, which is basically nothing. That is quite indicative that wanting to use an enum (in Rust, at least) is a rare edge case. Funny, given how concerned Rust users seem to be about enums. Talk is cheap, I suppose.
Java has true enums that are neither fancy integers nor discriminated unions. The following is not a list of integers:
public enum Day {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY
}
To use this enum, you typically declare a variable of type Day, which is a subclass of Enum, itself a subclass of Object, which cannot be cast to or from int. If a variable is typed as Day, then it can only take one of these variants (or null). Even though the Day class does have an ordinal() method, and you can look up the variants by ordinal, you cannot represent Day(7) or Day(-1) in any way, shape, or form. This sealed set of variants is guaranteed by the language and runtime (*). Each variant, like SUNDAY, is an instance of class Day, and not a mere integer. You can attach additional methods to the Day class, and those methods do not need to anticipate any other variants than the ones you define. Indeed, enums are sometimes used with a single variant, typically called INSTANCE, to make true singletons.
* = There is a caveat here, which is that the sealed set of variants can differ between compile-time (what's in a .java file) and runtime (what's in a .class file) but this only happens when you mismatch your dependency versions. Rather importantly, the resolution of enum variants by the classloader is based on their name and not their ordinal, so even if the runtime class differs from the compile-time source, Day.MONDAY will never be turned into a differently named variant.
Then I am not sure how you think it is an enum? What defines an enum, literally by dictionary definition, is numbering.
It is hilarious to me that when enum is used in the context of looping over an array, everyone understands that it represents the index of the element. But when it comes to an enum in a language, all of a sudden some start to think it is magically something else? But the whole reason it is called an enum is because it is produced by the order index of an AST/other intermediate representation node. The very same thing!
While I haven't looked closely at how Java implements the feature of which you speak, I'd be surprised if it isn't more or less the same as how Rust does it under the hood. As in using a union with an enumerator producing the discriminant. In this case it would be a tag-only union, but that distinction is of little consequence for the purposes of this discussion. That there is an `ordinal` method pretty much confirms that suspicion (and defies your claim).
> you cannot represent Day(7) or Day(-1) in any way, shape, or form.
While that is true, that's a feature of the type system. This is a half-assed attempt at sum types. Enums, on the other hand, are values. An enum is conceptually the same as you manually typing 1, 2, 3, ... as constants, except the compiler generates the numbers for you automatically, which is what is happening in your example. The enum is returned by `ordinal`, like you said. Same as calling std::mem::discriminant in Rust like we already discussed in a sibling thread.
The existence of the ordinal method reveals nothing except that the ordinal exists. It can be (and is) simply a field on each Day object, not an index into anything (though the Day objects are probably stored in an array, this is not required by any property of the system). Day.SUNDAY is ultimately a pointer, not an int. It is also a symbolically resolved pointer, so it will never become Day.MONDAY even if I reorder the variants so that their ordinals are swapped. The ordinal is not a discriminant.
You seem to be trivializing the type system. This property is not imagined solely by the compiler, it is carried through the language and runtime and cannot be violated (outside of bugs or unsafe code). Go has nothing like this.
If you choose to call this "not an enum", that is certainly your idiosyncratic prerogative, but that doesn't make for very interesting discussion. Even though I agree that discriminated unions aren't enums and am somewhat annoyed by Rust's overloading of the term, this is not that.
> The existence of the ordinal method reveals nothing except that the ordinal exists.
It strongly suggests that implementation is a discriminated union, just like Rust. Again, it is tag-only in this case, where Rust allows also attaching payload, but that's still a type of discriminated union. That it is a set of integers – contrary to the claim made earlier – combined with you explaining how the compiler treats it like a discriminated union — as in that there are type checks against the union state, that does reveal that it couldn't be anything other than a discriminated union that is effectively identical to what we find in Rust, along with many other languages these days.
> It can be (and is) simply a field on each Day object, not an index into anything
So...? Enum is not staunch in exactly where the number comes from; it simply needs to number something. Indices are convenient, though, and I am not sure why you would use anything else? That doesn't necessarily mean the index will start where you think it should, of course.
For example,
enum Foo { A, B, C }
enum Bar { X, Y, Z }
In some languages, the indices might "reset" for each enum [A=0, B=1, C=2, X=0, Y=1, Z=2], while in other languages it might "count from the top" [A=0, B=1, C=2, X=3, Y=4, Z=5]. But, meaningless differences aside, where else is the number going to come from? Using a random number generator would be silly.
But, humour us, how does Java produce its enums and why doesn't it use indices for that? Moreover, why did they choose to use the word `ordinal` for the method name when that literally expresses that it is the positional index?
Setting aside the full enum API, as well as certain optimizations, this is a rough equivalent of the enum I gave:
public class Day extends Enum<Day> {
private int _ordinal;
private Day(int ordinal) { this._ordinal = ordinal; }
public int ordinal() { return this._ordinal; }
public static final Day SUNDAY = new Day(0);
// ...
public static final Day SATURDAY = new Day(6);
}
with the added constraint that the Day constructor cannot be invoked by reflection, and the static instances shown herein can be used in a switch statement (which may reduce them to their ordinals to simplify the jump table). Each instance is ultimately a pointer, so yes it could be pulled from a sort of RNG (the allocator). As I said they are probably in an array, so it's likely that the addresses of each variant start from some semi-random base but then increase by a fixed amount (the size of a Day object). A variable of type Day stores the pointer, not the ordinal.
Now, it really seems to be in the weeds of pedantry when you start talking about discriminated unions that have only discriminants and no payload. Taking from your examples, the key point is that a Foo is not a Bar and is also not an int. Regardless of whether the variants are distinct or overlapping in their ordinals, they are not interchangeable with each other or with machine-sized integers.
Yes, this echos what I stated earlier: "An enum is conceptually the same as you manually typing 1, 2, 3, ... as constants, except the compiler generates the numbers for you automatically" Nice to see that your understanding is growing.
> Taking from your examples, the key point is that a Foo is not a Bar.
I'm not sure that's a useful point. Nobody thinks
class Foo {}
class Bar {}
...are treated as being the same in Java, or, well any language that allows defining types of that nature. That is even the case in Go!
type Foo int
type Bar int
const f Foo = iota
const b Bar = f // compiler error on mismatched types
But what is significant to the discussion about enums is the value that drives the inner union of the class. As in, the numbers that rest beneath SUNDAY, MONDAY, TUESDAY, etc. That's the enum portion.
I don't understand anything more now than I did at the start. It is clear we are talking past each other.
The values of Day are {SUNDAY, ..., SATURDAY} not {0, ..., 6}. We can, of course, establish a 1:1 mapping between those two sets, and the API provides a convenient forward mapping through the ordinal method and a somewhat less convenient reverse mapping through the values static method. However, at runtime, instances of Day are pointers not numbers, and ints outside the range [0, 6] will never be returned by the ordinal method and will cause IndexOutOfBoundsException if used like Day.values()[ordinal].
Tying back to purpose of this thread, Go cannot deliver the same guarantee. Even if we define
type Day int
const (
Sunday Day = iota
// ...
Saturday
)
then we can always construct Day(-1) or Day(7) and we must consider them in a switch statement. It is also trivial to cast to another "enum" type in Go, even if the variant doesn't exist on the other side. This sealed, nonconvertible nature of Java enums makes them "true" enums, which you can call tag-only discriminated unions or whatever if you want, but no such thing exists in Go. In fact, it is not even possible to directly adapt the Java approach, since sealed types of any kind, including structs, are impossible thanks to new(T) being allowed for all types T.
> This sealed, nonconvertible nature of Java enums makes them "true" enums, which you can call tag-only discriminated unions or whatever if you want, and no such thing exists in Go.
It is no secret that Go has a limited type system. In fact, upon release it was explicitly stated that their goal was for it to be a "dynamically-typed language with statically-typed performance", meaning that what limited type system it does have there only to support the performance goals. You'd have to be completely out to lunch while also living under a rock to think that Go has "advanced" types.
But, as before, enums are values. It is not clear why you want to keep going back to talking about type systems. That is an entirely different subject. It may be an interesting one, but off-topic as it pertains to this discussion specifically about enums, and especially not useful when talking in the context of Go which it isn't really intended to be a statically-typed language in the first place.
Funny enough, manually defining the discriminant disables the enumerator:
enum Discriminant1 {
Disc0,
Disc1,
}
#[repr(u8)]
enum Discriminant2 {
Disc0 = 10,
Disc1 = 20
}
fn main() {
let d1 = Discriminant1::Disc1;
let d2 = Discriminant2::Disc1;
println!("{:?}", std::mem::discriminant(&d1)); // Value by enumerator.
println!("{:?}", std::mem::discriminant(&d2)); // Value by constant.
}
Which makes the use of the enum keyword particularly bizarre given that there is no longer even an enumerator involved, but I suppose bizarre inconsistencies are par for the course in Rust.
And because it has been used like that in C for decades, the dictionary definition takes a backseat to the now de-facto C-based definition (at least for popular systems languages, which Rust is trying to share as much syntax with).
Meaning the keyword? Sure, C has the same inconsistency if you disable the enumerator with manual constant values. C is not exactly the paragon of thoughtful design. But whataboutism is a dumb path to go down.
> the dictionary definition takes a backseat to the now de-facto C-based definition
That's clearly not the case, though, as the functionality offered by the Rust enum keyword is very different. It puts absolutely no effort into being anything like C. Instead, it uses enum as the keyword for defining sum types. The C enum keyword, on the other hand, does nothing but define constants, and is functionally identical to what Go has. There is an enum involved in both cases, as demonstrated earlier, so the terminology isn't strictly wrong (in the usual case) but the reason for it existing shares little commonality.
But maybe you've moved onto the concept of enums rather than syntax and I didn't notice? You are right that the dictionary definition is in line with the intent of the C keyword, which speaks to the implementation, and is how C, Rust, Go, and every other language out there use the terminology. In another comment I even linked to the implementation in both Go and Rust and you can see that the implementation is conceptually the same in both cases: https://news.ycombinator.com/item?id=44236666
reply