Comments (133)
Why not a ** b
to represent a ^ b
? Prevents problems and confusion with the XOR operator, and should be quickly apparent.
from csharplang.
Let's have a vote...
Symbol | Emoji | Note |
---|---|---|
^^ |
👍 | |
*^ |
🚀 | |
** |
❤️ | I doubt that the LDM would approve changing the lexer for this though - it already lexes as multiplication + pointer dereference and lexing based on identifier types will result in a complex implementation |
Another symbol | 👀 | Please comment the operator you want |
from csharplang.
Is this really so much better than
using static System.Math; var result = Pow(a, b);
It is.
Exponentiation is no different from addition or multiplication: it is a common mathematical operation for which there is a universal notation (including precedence rules) that is approximated in programming languages.
C doesn't have an exponentiation operator, while it does have operators for closer to the metal operations like bit-wise xor (^
) and integer shifts. It seems java and C# inherited this design more or less by default without fully considering its merits. Most modern languages that are more oriented towards user-experience (Python, VB, R...) do have an exponentiation operator.
Furthermore, while operators are in scope and will be used when the defining type is in scope, this is not true for the static import in your example. It doesn't work within the scope of a type that itself defines a Pow
method, such as a complex number type or a vector type.
VB's
^
operator literally just translates into a call toMath.Pow
Not exactly. There are some small differences. For example, the LINQ expression tree for the VB operator uses a binary expression of type Power
(where the Method
is Math.Pow
), while C#'s version uses a method call.
@gregsdennis It is possible to overload the VB operator from C# manually, i.e. by defining a static op_Exponent
method with a SpecialName
attribute. You can do the same for F#, but the operator method is called op_Exponentiation
(section 4.1 of the F# language spec). This is an unfortunate and annoying inconsistency.
It would be better if this was all consistent: have all common mathematical operations available as operators that can be overloaded in the same way and that makes them accessible to all .NET languages.
from csharplang.
I agree that the syntactic ambiguity of **
is a large negative to the point where it's likely not worth the trouble.
D and Haskell use ^^
, which isn't great, but isn't terrible, either. It does not have any syntax issues that I'm aware of.
To give you an idea of how common the operation is, I looked at one of our projects, which is heavy on technical computing. About 0.9% of code lines contains an exponentiation. It is much more common than shifts or xors. Element-wise operations on arrays/collections are also quite common.
Although it is not primary evidence of commonality, the fact that the operator is included in many programming languages suggests that others found it sufficiently common to include in the language. Some of these languages had very tight constraints, like Altair BASIC, which fit in 8192 bytes (see manual (PDF), page 27).
Microsoft provides tooling for many languages that have the exponentiation operator:
- All Microsoft BASIC dialects, including VBScript, VBA, and VB.NET
- Microsoft F#
- Microsoft TypeScript 1.7 and ES7
- Microsoft Excel
- Python
- R
from csharplang.
it is a common mathematical operation
Citation? :)
from csharplang.
A ** operator would be superfluous. It's just a call to Math.Pow. :)
from csharplang.
I think more pertinent to this specific use case is that the operator can be overloaded whereas Math.Pow()
cannot.
from csharplang.
If you're in the type itself, you don't need the static import. You can just directly call "Pow(x, y)"
But you can't access another type's Pow
method that is statically imported without qualifying.
In the code below, class A
's M
method is successfully called from class B
. However, in class C
, the presence of the M
method prevents it from being considered, unless you qualify it:
namespace N1
{
public class A
{
public static void M(string x) { }
}
}
namespace N2
{
using static N1.A;
public class B
{
public void M2()
{
M("Test"); // OK
}
}
public class C
{
public static void M(int x) { }
public void M2()
{
M(12); // OK
M("Test"); // 'Argument 1: Cannot convert from string to int'
N1.A.M("Test"); // OK
}
}
}
Citation? :)
This is like someone from Texas asking a Canadian for a citation that snow is a common weather phenomenon. :) Just because something isn't common in your experience doesn't mean it's not common for other people.
But since you asked: the code sample in the documentation for the static using
directive contains two squares, written out as multiplications.
from csharplang.
Just because something isn't common in your experience doesn't mean it's not common for other people.
And just because it's common for you, doesn't mean it's common enough to warrant inclusion in the language. :)
This is like someone from Texas asking a Canadian for a citation that snow is a common weather phenomenon
No. This is like a member of the LDM asking you what the basis of your claim is.
from csharplang.
Yes, a **
operator would be nice.
However, would it be possible to add this operator and not interfere with the dereference operator (*
)? I guess since the dereference operator works on pointers, which aren't used in exponentiation operations, this seems like it would be OK.
F# also uses **
. F# - Arithmetic Operators
from csharplang.
I have now seen that the comment i replied to has been deleted. So i'd like to nip this side of the conversation in the bud. My overall point is simply that this seems to be a feature without that much impact with very little interest.
--
From a technical perspective, i'm also worried about breaking changes here. Today, this is already legal code:
unsafe void X(int* p, int c)
{
var v = c**p
}
We'd likely have to do some sort of unpleasant contortions to ensure we didn't break existing code like this.
from csharplang.
VB's ^
operator can be used in constants.
from csharplang.
It's not clear to me that **
as an operator would cause an issue due to a conflict with the dereferencing operator.
Currently, in C#:
&
is used to obtain an address&
is used for logical AND&&
is conditional AND
There clearly aren't any implementation issues there.
Considering the example given above:
var v = c**p;
The above **
cannot be interpreted as a exponentiation operator because that would require treating p
as an exponent and p
is a pointer.
I'm fairly neutral regarding **
vs ^^
. However, **
seems more common. If there isn't a strong technical reason against **
, it seems like a good option.
from csharplang.
@LMLB 's argument is the most convincing to me- C# 7.0 is adding digit separators and binary literals for the "defining a constant" use case, and this seems at least as useful as either of those features.
from csharplang.
A sqrt operator would be superfluous. It's just x^^0.5
; a special case of <1 exponentiation.
from csharplang.
@Korporal Today:
[FlagsAttribute]
enum SingleHue : short
{
None = 0,
Black = 1 << 0,
Red = 1 << 1,
Green = 1 << 2,
Blue = 1 << 3
};
Also today:
[FlagsAttribute]
enum SingleHue : short
{
None = 0b0000,
Black = 0b0001,
Red = 0b0010,
Green = 0b0100,
Blue = 0b1000
};
from csharplang.
it is a common mathematical operation
Citation? :)
API Port telemetry says that Math.Pow()
is used in 11 % of apps. Not sure if that is common enough.
Is exponentiation more common or important than square root? Where do you draw the line of which operations are important enough to deserve an operator?
The same data says that Math.Sqrt()
is used in 7 % of apps. So it is less common than exponentiation, but not by much. But while it's fairly easy to come up with decent operators for exponentiation (whether it's **
or ^^
), I don't see what would be a good operator for square root (I don't think √ a.k.a. U+221A SQUARE ROOT is an option).
from csharplang.
Is this really so much better than
using static System.Math;
var result = Pow(a, b);
from csharplang.
Furthermore, while operators are in scope and will be used when the defining type is in scope, this is not true for the static import in your example. It doesn't work within the scope of a type that itself defines a Pow method, such as a complex number type or a vector type.
If you're in the type itself, you don't need the static import. You can just directly call "Pow(x, y)"
from csharplang.
A ** operator would be superfluous. It's just a call to Math.Pow. :)
Can't this be a constant expression?
from csharplang.
Scientific programming is more cumbersome, error prone, and difficult to read when done in C# due to missing exponent operator. I am considering spiting some equation code out into a small F# library just to make it cleaner and avoid a series of Pow method calls. I should not have to do this: exponential operator IS a standard need for many use cases. Why else would so many languages have it?
from csharplang.
Is this really so much better than
using static System.Math; var result = Pow(a, b);
It also would enable operator overloading for custom numerical types (e.g. complex numbers etc.)
from csharplang.
Is exponentiation more common or important than square root? Where do you draw the line of which operations are important enough to deserve an operator?
The only benefit, IMHO, is that you can use mathematical operators statically. However, I think the constexpr feature (dotnet/roslyn#15079) is a lot more general so I'd be in favor of that to fulfill that use case rather than adding a new operator.
from csharplang.
or on the BCL side, some math functionality in classes, etc.; and then prioritize those and tackle 1 or 2 every version.
This is independent of the language and is as simple as opening an API proposal here: https://github.com/dotnet/runtime/issues/new?assignees=&labels=api-suggestion&template=02_api_proposal.yml
I'm the area owner and the person who would drive such proposals forward
- Provided I agree with the use case and that it would be beneficial, etc. I'm generally open to hear ideas, discuss them, and get feedback, so please open an issue or start a discussion thread and tag me if you have an idea
Basically, it's not "all or nothing"; small steps can add up over time; and it does not mean turning away from generality.
Certainly, and both C# and .NET in general have made leaps and bounds here, particularly in the BCL and what it supports natively. I've listed per release changes below and I've probably missed a few :)
C# 1.0/.NET 1.0 (2002)
Integer Types
- SByte, Int16, Int32, Int64
- Byte, UInt16, UInt32, UInt64
- IntPtr, UIntPtr
Floating-Point Types
- Single, Double
System.Math
- Mostly double-precision float support
- A few operations had Integer or single-precision float support
.NET 4 (2010)
System.Numerics introduced
- BigInteger
- Complex
Initial SIMD Support, Out of Band (2014)
New Types
- Vector
- Vector2, Vector3, Vector4
- Matrix3x2, Matrix4x4
- Plane, Quaternion
Generally graphics oriented, minus Vector which was general purpose
.NET Core 2.0 & 2.1 (2017-2018)
System.MathF
- APIs supporting
float
Start of push for IEEE 754 compliance
- IsFinite, IsNegative, IsNormal, IsSubnormal
- Acosh, Asinh, Atanh, Cbrt
.NET Core 3.0 & 3.1 (2019)
More IEEE 754 Math
- BitIncrement, BitDecrement
- CopySign
- FusedMultiplyAdd
- MinMagnitude, MaxMagnitude
- ILogB, Log2, ScaleB
Additional Rounding Modes
- ToNegativeInfinity, ToPositiveInfinity, ToZero
Floating-point parsing/formatting fixes
x86/x64 Hardware Intrinsics
- Vector64, Vector128, Vector256
- SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, AVX2, FMA
- AES, BMI1, BMI2, LZCNT, PCLMULQDQ, POPCNT
System.Numerics.BitOperations introduced
- LeadingZeroCount, TrailingZeroCount, PopCount
- Integer based Log2
- RotateLeft, RotateRight
.NET 5 (2020)
New Types
- System.Half
- nint, nuint
New Math APIs
- Tau
- BigMul
Interchange APIs between System.Numerics and System.Runtime.Intrinsics vector types
ARM64 Hardware Intrinsics
- AdvSimd, DP
- AES, CRC32, RDM, SHA1, SHA256
.NET 6 ( 2021)
More Math APIs
- nint, nuint support
- Tuple returning DivRem
- ReciprocalEstimate, ReciprocalSqrtEstimate
- SinCos
Random.NextInt64
System.Numerics APIs
- BitOperations.IsPow
- BitOperations.RoundUpToPowerOf2
- Vector nint & nuint support
- Vector.Sum
Generic Math Preview: https://devblogs.microsoft.com/dotnet/preview-features-in-net-6-generic-math/
.NET vFuture
Generic Math (dotnet/designs#205)
Cross Platform Hardware Intrinsic Helper APIs (dotnet/runtime#49397)
Numerous other approved APIs and changes: https://github.com/dotnet/runtime/issues?q=is%3Aopen+is%3Aissue+label%3Aarea-System.Buffers%2Carea-System.Numerics%2Carea-System.Numerics.Tensors%2Carea-System.Runtime%2Carea-System.Runtime.Intrinsics+label%3Aapi-approved+approved
- nint/nuint support for hardware intrinsics
- General Purpose CRC32 APIs
- Support for parsing/formatting hexadecimal based floats
- DivMod intrinsic for x86/x64
- TableVectorLookup intrinsic for ARM64
- ShiftLeft/ShiftRight APIs for Vector and xplat hardware intrinsics
- more missing math functions
- etc
from csharplang.
Having to refactor projects to gain easy access to an operator is a big ask. To accomplish what I need, I'd also have to move common types needed by both libraries into a new library. So library A is split into A1,A2,A3, simply to have more readable exponential code.
from csharplang.
Having said that, given how many other languages have an operator for exponents, and that it's a very common notation in mathematical equations/formulas, it does seem like a glaring omission.
But it's not all that common in general programming. It's a slippery slope as to which of the many arithmetic operations should be promoted to language operators. C# will never be written like arithmetic formulas. Neither will Python for that matter. Having to change the language seems unnecessary when the operation can be exposed as a method.
from csharplang.
Yes, VB has it so it makes translation easier, also makes mathematical expression easier to read but the second point could be debated.
Sent from my iPhone
I apologize for any typos Siri might have made.
(503) 803-6077
On Aug 18, 2015, at 11:31 AM, Neal Gafter [email protected] wrote:
Is this really so much better than
using static System.Math;
var result = Pow(a, b);
—
Reply to this email directly or view it on GitHub.
from csharplang.
Why else would so many languages have it?
By this argument, every language should have every feature that is in several other languages :)
I am considering spiting some equation code out into a small F# library just to make it cleaner
That seems reasonable. I mean... this is why there are so many .net languages (including several owned by MS). Each have their respective strengths, and you should pick the right one for the code you're working on, rather than trying to make each one have all the features of the others. :)
from csharplang.
Part of what makes C#
C#
is that it is a generalist language.
I agree, and that's exactly why I prefer it to other languages.
Put another way. Adding exponentiation isn't going to be the feature that substantively moves the dial here (IMO). So we should either commit to 'math oriented' being a goal of hte language (with a broad look at the future direction and what that would mean), or we should take it as what it is, and not just add a one-off feature here and there because it's an annoyance to a specific group.
I understand this perfectly, and here's my suggestion: why not collect a list of potential improvements to make C# more math-friendly, be it an operator here, or some construct there, or on the BCL side, some math functionality in classes, etc.; and then prioritize those and tackle 1 or 2 every version. That way, eventually the language will be decently usable for math projects and it can be offered as a viable alternative to beginners who want to solve math problems, particularly scientists and science students. That would be a great new source of user base. Some recent changes have already been made in that direction, such as top level programs (whether intentionally or not). Another addition might be a REPL that's supported by the language team.
Basically, it's not "all or nothing"; small steps can add up over time; and it does not mean turning away from generality.
from csharplang.
An exponentiation operator is generic (general-use, not type generic), not a special case like a sqrt operator would be.
from csharplang.
@dharmatech There is no ambiguity with && because && is always parsed as the short-circuit and operator. Same thing with ++ and --: c = a++b
is a syntax error because ++ is interpreted as the increment operator. It would have been a little bit harder to do for ** (because multiple derefs on one value are possible and meaningful), but it's simply too late now.
@gregsdennis There is decades of precedent for an exponentiation operator (FORTRAN-66 had it), but none for a square root operator. Not even APL has one.
@CyrusNajmabadi It actually gets even more complicated with precedence rules and the fact that pow is right-associative. For example, a * b ** c
is now parsed as (a * b) * (*c)
, but the correct interpretation with pow is a * (b ** c)
. So you can have a semantic tree that is very different, even structurally, from the syntax tree. You can't just say that the multiplication is really a power, and the deref is really a no-op: The arguments are different.
@svick Very interesting, thanks! That's probably a slight under-estimate because squares (and other small powers) are often optimized into multiplications. Math.Pow is 2 orders of magnitude slower than squaring by multiplying (but that's a different issue).
from csharplang.
I completely agree with t9mike. This not just a semantic win, but a performance win. Also, being able to use exponentian in a const is the slam dunk.
from csharplang.
Is this really so much better than
using static System.Math; var result = Pow(a, b);
Not hugely but it would be neat when defining constants that are powers of some other constant, e.g.
public static class Values
{
public const double RATE_1 = Math.Pow(10, 2); // elicits CS0133
public const double RATE_2 = 10 * 10;
public const double RATE_3 = 10 ** 2; // would be a nice feature
}
There are occasions where its very helpful to define sets of constants explicitly in terms of powers of 2 or 10.
A similar thing applies to enums where we want to explicitly define flags for example, it is very natural and readable to define these as explicit powers of 2 sometimes (yes there are other ways).
from csharplang.
@CyrusNajmabadi think about it this way: yes currently there aren't many people on this thread requesting the exponent operator, and that's because there aren't many who use C# for mathematically-focused workloads. And that's because they're all using other languages, specifically one very venomous one. I think this is actually a very worthy investment for C#, and this is coming from a programmer who almost never uses exponents.
from csharplang.
It would cause a syntactic ambiguity. Today we parse "a**b" as "a * (*b)" i.e. "a times the deref of b". With this new operator, we'd now parse that as "a ** b".
We do not change parse trees for correct code. So we would have to still parse things like the old way, but at semantics time, see if we had this pattern, and we'd have to determine what would be the right thing to do.
If the code isn't in unsafe
mode, then **
is unambiguously exponentiation.
If you are in unsafe
mode and the right operand of **
is a pointer, then dereference and multiply. Otherwise, exponentiation.
from csharplang.
an int raised to an int powers is always an it.
I think the reason that
Math.Pow
was returndouble
even you input anint
because2^33
is larger thanint
. And2^65
is even larger thanlong
. We have no integer type to capture it
I know.
However a purely int ** int support would be a neat addition to the language. It doesn't exist yet and so would not be a breaking change.
Defining constants that involve exponentiation - as I mentioned - seems to me to almost always be int ** int anyway and this is where I'd find the feature most useful as well as for operator overloading.
Of course a negative exponent will lead to non integer results but these are always rational numbers and could be represented as decimal...
from csharplang.
So do others think this proposal should be amended to restrict the scope of a new ** operator to integers and with positive exponents? Since this would be an entirely new operator it would not be a breaking change and since we already have Math.Power() which is itself confined to float/double the restricted scope of ** is not unreasonable?
The benefits of this restricted operator are therefore:
- Requires no support from the C runtime library.
- Can be reliably calculated at compile time and runtime by sharing the (new) implementation.
- Would be platform agnostic.
- Becomes available for use in defining compile time constant expression that use ** for readability.
from csharplang.
C++ once considered *^
but nobody pursued this option.
This is like private protected
- it's similar to existing operators but a bit different. Thoughts?
from csharplang.
^^
would be more natural to type though. C++'s rationale for this breaking the expectation of &&
being short-circuit &
and ||
being short-circuit |
doesn't really hold because there is no way to short-circuit ^
.
from csharplang.
Just noting here that neither ^^
and *^
can be used, much like *
, due to the existence of ^
as both a binary and a preceding unary operator (indexing from the end). This means we have to either consider a completely unrelated symbol to denote exponentation, or use a 3-symbol operator like:
**^
^**
*^*
None of those can cause syntactic ambiguity yet, but ^**
could prohibit usage of the ^
operator after an expression for whatever purpose it could be reserved for, causing the ambiguity between (a^) * (*b)
and (a) (^**) (b)
(parentheses used for grouping; actual syntax would be invalid).
Speaking of the above, parenthesizing the operators for grouping is another valid solution, which would allow for extending the **
operator to supporting higher hyperoperators by concatenating *
s together (***
for power towers, ****
for power tower towers, etc.). In this case, exponentation would be denoted as a (**) b
, resolving any syntactic ambiguities.
from csharplang.
My concern, particularly as someone who works frequently with unsafe code and numerics, is that its going to make being able to read and reason about the code that much harder.
My own cognitive load is going to increase as it can now also mean exponent
(in addition to multiply
or dereference
) and the exact whitespace, left/right hand side types, and more can change how its interpreted which is going to make reviewing PRs involving these a pain.
It would be slightly better if whitespace requirements were consistent, but its not. Likewise, while multiplying by a pointer doesn't necessarily make sense, its also already allowed for user-defined operators which makes it even more complicated:
public unsafe static C operator *(C left, int* right) => throw null;
More in general (and I believe I've commented on similar proposal before) I'm still not convinced of the overall value here:
- The general perf of these functions isn't going to be great
- A deterministic and IEEE 754 compliant function would need to be written for floating-point
- Such an operator likely needs to get worked into generic math (and all the considerations it entails)
- This is going to have to consider
checked
behavior which will overflow for even simple inputs because the maximum inputs is2^63
for aulong
. As the LHS goes up, the RHS goes down; so most inputs will overflow and not be useful (the allowed inputs end up being fairly precise otherwise:4294967296^2
,2097152^3
,65536^4
,4096^5
, etc; where afterx^5
you start getting into fractionals and numbers that don't work for integers)- I imagine the most common usages here are for powers of 2, in which case better BCL based options exist
- For integer types, the RHS cannot be negative (or must truncate to
0
if it is) - BigInteger itself is a slightly different story where it can be beneficial to support and where the type already exposes an API
To me, it would be helpful to see some real world sample code that:
- Needs exponent operations and frequently
- Where the readability of the code is significantly improved by having an exponentiation operator rather than breaking apart the algorithm with a
Math.Pow
call.
In my own experience, both of these are rare and are limited to BigInteger or floating-point. The places where I commonly need similar for integers deals with powers of 2 (where left/right shift is a better option) or constants.
from csharplang.
It's not clear to me that ** as an operator would cause an issue due to a conflict with the dereferencing operator.
It would cause a syntactic ambiguity. Today we parse "a**b" as "a * (*b)" i.e. "a times the deref of b". With this new operator, we'd now parse that as "a ** b".
We do not change parse trees for correct code. So we would have to still parse things like the old way, but at semantics time, see if we had this pattern, and we'd have to determine what would be the right thing to do.
from csharplang.
It's not clear to me that ** as an operator would cause an issue due to a conflict with the dereferencing operator.
There is clearly a conflict here. The question is: is that acceptable? For example, there's a syntactic ambiguity with: (A)-B. That could be "minus B, casted to the A type". Or it should be "the value of parenthesized expr A, minus the value of B". We went with the former for C#. But once we decide on something, we don't change it**.
Here, we'd have to always parse this as "A times the deref of B". But we'd then have to have some special rule that says "if you have that, and there is no space between the operators, and B is derefable, then behave like so, otherwise, behave like so". That's pretty janky, and not something we've ever done before really.
--
** Ok, we also changed it for generic parsing: X(A<B, D>(E))
We changed the parsing here to make this into a nested invocation call, instead of two relational expressions. However, we're very wary of changing parsing. And i'm personally of hte opinion that it's very janky for us to special case the treatment of "a ** b" to processed differently depending on if 'b' is dereferencable or not.
from csharplang.
Can you explain what you'd consider a full numeric tower? Maybe some links?
Ah, sorry. :-) It's a term used in the Lisp and Scheme worlds.
So I just meant that, once you have arbitrary precision integers and rationals available in a language, an exponential operator starts to make sense for many more of the cases that were considered awkward when only the native types are available (the cases you mentioned like fractional, negative, and large exponents).
The exponentiation operator proposal here is not only intended for the native types (it should have some reasonable defaults for these wherever possible) but to also serve in the case where the user would like to use the operator in the context of a more complete numerical library.
So for example, even if the team decided that the basic ^^
operator only worked on double
(I'd be OK with that. This is how the default **
operator works in F#, for example.), it could be overloaded by users and library designers of more complete numeric libraries.
from csharplang.
I need this
from csharplang.
maybe we can use #
as pow operator.
let us SHARP #
:
var a = b#c;
:)
from csharplang.
That way, eventually the language will be decently usable for math projects
Here's hte disconnect. The view on what it 'decently usable'. There isn't consensus on this, and you'll have the spectrum of people going:
- it already caters too much to math. Yes, we have this with people who don't like things like operating overloading.
- it caters just fine to it. lots of thigns work nicely, and it's not a great burden to colorize outside of those lines.
- it doesn't go far enough at all. we need lots more features.
We cannot, and should not necessarily cater to '3' all the time. Even if it's trickling in, it's not necessarily a goal for c# to get to that point, and it can actively be seen as harmful as all that complexity now has to be worked through (both at the individual level, and how it affects everything else).
small steps can add up over time;
So, IMO, we already do this. It's just that that genuinely may mean that a particular feature (like this one) just may not be relevant. It might be, for example, that we extend things like operators to work on tuples/arrays/etc. as that may be more pressing and much more painful to not have.
So even if we go this route, I would say that you should not expect that that would mean that exponentiation would ever meet the bar as needing direct lang syntax.
from csharplang.
Why not a ** b to represent a ^ b? Prevents problems and confusion with the XOR operator, and should be quickly apparent.
👍
from csharplang.
VB's ^
operator literally just translates into a call to Math.Pow
so there is no additional benefit to porting between the languages. There is also nothing stipulating feature parity or direct porting of programs between the two languages and there are plenty of features between the two that cannot translate.
The second argument about math operations being easier to read is the more relevant argument in my opinion.
from csharplang.
Related #14665 but like @MgSam said please check #15079, if you like the idea join the discussion. :)
from csharplang.
Claim: the scientific computing community needs better representation on the C# LDM.
Citation: this thread.
This thread has 16 comments over an entire year of being open. There are only about 8 non-MS people even commenting on this. This seems to have very little interest (contrast with threads with dozens of people and hundreds of messages). Furthermore, the existence of interest does not mean that we should ,or will, take a request. We have literally hundreds to thousands of small requests like this. We definitely will not be taking the vast majority of them. We have to actually consider how important this is to the entirety of our ecosystem. Right now, the interest and impact of this feature are both low.
from csharplang.
If you are in unsafe mode and the right operand of ** is a pointer, then dereference and multiply. Otherwise, exponentiation.
yes. this could be done. But now we have the same syntax meaning different things with operators. I'm not a fan of this. ++ doesn't mean something different depending on context. i.e. we don't say "oh, in a++b, there is no ++ operator for 'a', this this is 'a added to plus-b'".
from csharplang.
API Port telemetry says that Math.Pow() is used in 11 % of apps. Not sure if that is common enough.
I'd want to know how often it was actually used. If 11% of all apps use the call once, then i have no problem with them using Math.Pow. :)
from csharplang.
I don't go against the proposal but
a * b ** c
is now parsed as(a * b) * (*c)
Do we have a way to correctly parsed this?
Isn't *c
could be pointer denotes expression?
from csharplang.
A neater solution to that particular problem would be something like #2379
from csharplang.
@YairHalberstadt - Yes you're right but that in turn depends on C# supporting "pure functions" (or rather referential transparency in functional parlance). I do not know if this latter feature is moving along though.
from csharplang.
Not hugely but it would be neat when defining constants that are powers of some other constant, e.g.
This wouldn't be possible without the compiler implementing a software version of Pow
internally
Most of the math functions currently call into the C Runtime library and are non-deterministic across platforms (and are also not IEEE compliant).
It's a hard backlog item I've been tracking and hope to get fixed eventually, but that will only be available from CoreCLR.
from csharplang.
Not hugely but it would be neat when defining constants that are powers of some other constant, e.g.
This wouldn't be possible without the compiler implementing a software version of
Pow
internallyMost of the math functions currently call into the C Runtime library and are non-deterministic across platforms (and are also not IEEE compliant).
It's a hard backlog item I've been tracking and hope to get fixed eventually, but that will only be available from CoreCLR.
@tannergooding - C runtime library? the C# compiler has a dependency on that? I guess there's a reason why the compiler can't simply call Pow?
from csharplang.
C runtime library? the C# compiler has a dependency on that?
Not the C# compiler directly, but the runtime does (as does basically every program in existence, since basically no one wants to reimplement everything themselves 😄).
I guess there's a reason why the compiler can't simply call Pow?
As I mentioned, Math.Pow
just forwards to the C Runtime implementation for the current platform. This currently makes the result it returns non-deterministic as various platform/architecture/os configurations all implement it slightly differently.
from csharplang.
C runtime library? the C# compiler has a dependency on that?
Not the C# compiler directly, but the runtime does (as does basically every program in existence, since basically no one wants to reimplement everything themselves 😄).
I guess there's a reason why the compiler can't simply call Pow?
As I mentioned,
Math.Pow
just forwards to the C Runtime implementation for the current platform. This currently makes the result it returns non-deterministic as various platform/architecture/os configurations all implement it slightly differently.
@tannergooding - OK thanks I think I understand now, but how does the compiler perform this calculation then:
const double RATE = 1.03458711 * 2.88767357;
If the compiler can do that without calling the C runtime surely it's feasible to do exponentiation? Surely that line above involves some implementation of double multiplication and if so is there not a risk that that might differ slightly from what is eventually present at runtime?
In other words - if I understand you - the value of RATE when calculated by the C# compiler could in principle differ when the same two values are multiplied at runtime on some platform?
I see the ECMA C# standard states:
"The product is computed according to the rules of IEC 60559 arithmetic" (for float/double multiplication, page 173). I can see also that IEC 60559 is (it seems) identical to IEEE 754.
So how do you guarantee that floating point multiplication performed at compile time is identical to floating point multiplication performed at runtime?
from csharplang.
Because multiplication is a primitive operation supported directly by IL and, generally speaking, directly by your hardware as well. There is a strict definition for its implementation and the C# spec requires that things do that correctly.
Math.Pow
is a function call that is generally built by using multiple primitive operations, and while there is a strict IEEE compliant answer (which is, given the input values, it should compute the infinitely precise result and then round to the nearest representable result), not every platform implements that correctly and some make minor trade-offs favoring speed instead of precision.
This is, ultimately, the same reason why C# has it's own floating-point parser. Even though double.Parse
has a strict IEEE compliant result it should return, .NET used to have some bugs (which I fixed for .NET Core 3.0), that would cause it to sometimes return an incorrect result.
from csharplang.
not every platform implements that correctly and some make minor trade-offs favoring speed instead of precision.
It's also very easy to do implement something that isn't correct by accident. IEEE floating-point math != normal math.
For example, normal math states that a + b + c
is the same as (a + b) +c
which is the same as a + (b + c)
. However, in IEEE floating-point, this isn't the case as each value is actually just a rounded approximation of the actual value and each value has an epsilon (some even have two) which is the amount you need to add or subtract to become the next or previous representable value.
For example, say you have a function which computes the sum of all values in an array:
public static float Sum(float[] values)
{
var sum = 0.0f;
for (int i = 0; i < values.Length; i++)
{
sum += values[i];
}
return sum;
}
Now say you have 50,000
values where the first value is 500000f
and the remaining 49,999
values are 0.000001f
.
The result of this sum is 500000f
, because 0.000001f
is less than the epsilon between 500000f
and the next representable value (500000.03
).
Now, lets switch it up so that the first 49,999
values are 0.000001f
and the last element is 500000f
.
The result of this sum is 500000.06
, because the sum of the first 49,999
values is 0.049973357
and the nearest representable value to 500000 + 0.049973357
is 500000.06
(as it is slightly closer than 500000.03
).
It's also worth calling out that, if we were falling normal math rules the sum of the first 49,999
values would have been 0.049999
, (for which the nearest representable value is 0.0499989986419677734375
), but this falls into a similar situation as the first scenario, where due to values generally being an approximation (the nearest representable value) and due to values having different epsilons (which may make the addition do nothing) we don't actually return the "expected" result.
from csharplang.
@tannergooding - OK thanks for the explanation, clearly there are a lot of subtle issues to consider. But much of what you say is only relevant in the case of float/double yes?
The compiler could calculate integer exponentiation without too much trouble, an int raised to an int powers is always an it.
Also in almost all cases that I see, constants expressed using exponentiation are almost always integer, and most of those are either powers of 2 or 10.
So could this be implemented for integers at least?
from csharplang.
an int raised to an int powers is always an it.
I think the reason that Math.Pow
was return double
even you input an int
because 2^33
is larger than int
. And 2^65
is even larger than long
. We have no integer type to capture it
from csharplang.
We have no integer type to capture it
Off-topic but you can use BigInteger.Pow
even though Math.Pow(2, 65)
is perfectly valid.
from csharplang.
@eyalsk Well because I don't think that was the integer type. It actually a class and it was not support by Math.Pow
And also will it really fine to have exponent operator return BigInteger
as default?
from csharplang.
@Thaina I doubt it.
from csharplang.
@Korporal My point is what is the default return type you want for this operation?
If you think it should be Int32. Then whenever there was a code var x = 2**33;
should it be error in the compile time or throwing integer overflow at the runtime. Or just silently become int.MaxValue
?
If it was const int x = 2**33;
should it error or when it should throw exception?
Exponent was so easily go out of bound of the integer. Just 9^10 is larger than int32
so what should we do?
I think exponent is not practical to return as int32. We might need BigInteger or just accept double as return type
from csharplang.
@Thaina - Here's my quick analysis of that question.
The smallest int power we can use is 2, the smallest int we can raise to a power is 2 (well 1 but that leads to no change).
This means that a Byte
is sufficient for the exponent (disregarding -ve exponent support) because we can never even reach an exponent of 256 even for the smallest base of 2.
The largest result we can support is an Int64
(supporting +ve or -ve bases) that has a Max of 9223372036854775807.
The square root of that is the max value we could ever square (the smallest power we could use) which is 3037000499 which is B504 F333.
That exceeds the capacity of an Int32
so must be made an Int64
.
Therefore the signature is a single function:
public static Int64 Raise(Int64 Base, Byte Power)
from csharplang.
Another use of such a feature (that is when used to define compile time constants) is for defining flag enum values.
today:
[FlagsAttribute]
enum SingleHue : short
{
None = 0,
Black = 1,
Red = 2,
Green = 4,
Blue = 8
};
tomorrow (?)
[FlagsAttribute]
enum SingleHue : short
{
None = 0,
Black = 2 ** 0,
Red = 2 ** 1,
Green = 2 ** 2,
Blue = 2 ** 3
};
The latter is easier and less error prone to review when scanning the code visually and gaps or errors are likely easier to see, pretty helpful especially if the flags is a 32 or 64 bit int type where we might have a large list of flags.
from csharplang.
@Korporal Today:
[FlagsAttribute] enum SingleHue : short { None = 0, Black = 1 << 0, Red = 1 << 1, Green = 1 << 2, Blue = 1 << 3 };Also today:
[FlagsAttribute] enum SingleHue : short { None = 0b0000, Black = 0b0001, Red = 0b0010, Green = 0b0100, Blue = 0b1000 };
@svick - Yes I know, I was waiting for someone to point that out!
from csharplang.
should it be error in the compile time or throwing integer overflow at the runtime. Or just silently become int.MaxValue ?
It should mirror the current behaviour, and error with "compile time overflow" which can be overridden with the unchecked
syntax
from csharplang.
To be honest I don't like **
operator personally. But this is just totally personal. I can bear with it because some language already have it so it not unfamiliar
But because of reason above. I am more fond of #2379 and if I have to choose 1 I will choose to use Math.Pow
instead
But I won't go against this proposal and it would be useful to have if we can't use const Math.Pow
from csharplang.
@Thaina - Yes but bear in mind
To be honest I don't like
**
operator personally. But this is just totally personal. I can bear with it because some language already have it so it not unfamiliarBut because of reason above. I am more fond of #2379 and if I have to choose 1 I will choose to use
Math.Pow
insteadBut I won't go against this proposal and it would be useful to have if we can't use
const Math.Pow
@Thaina - Yes but bear in mind that #2379 itself relies on a - as yet - unavailable capability to tag code (either manually (dangerous) or automatically), as having referential integrity.
Unless the compiler "knows" that some static method has referential integrity #2379 cannot be delivered. I'm far from knowledgeable about how C# might do this but it strikes me as non-trivial. I don't even think F# can do #2379.
In addition I am now aware that the existing Math.Pow()
has no overloads and relies entirely on floating point arithmetic and can be (it seems) inconsistent across platforms.
Expressions of the form: int ** -int generate fractional results but these results are always rational numbers. This means that 10 ** -1 involves only integers and generates a result that can be expressed wholly as an integer fraction.
However in the case of Math.Pow() this result (0.1) is always represented as a float/double and 0.1 cannot be represented finitely as a binary fraction, so even with integer values Math.Pow() has scope for errors.
Of course int ** -int cannot have an integer result but it could (if we wanted it) express it's result as decimal.
So we could include this and have ** basically be:
public decimal (Int64, SByte)
The decimal type can (I think) represent any rational fraction possible when raising an Int64 to any negative value of an SByte without loss.
from csharplang.
The decimal type can (I think) represent any rational fraction possible when raising an Int64 to any negative value of an SByte without loss.
No, 3 ** -1
is not exactly representable as a decimal
.
from csharplang.
The decimal type can (I think) represent any rational fraction possible when raising an Int64 to any negative value of an SByte without loss.
No,
3 ** -1
is not exactly representable as adecimal
.
Yes you're quite right, I was confusing rational with finite expansion. So int ** -int could be removed, scope could be confined to Int64 ** Byte with a Int64 result...
from csharplang.
In my mind, the Pow
function is a little bit more complicated than the standard +
, -
, *
, and /
.
To me, it feels more like a sibling to functions like Sqrt
and Log
. There are all these cases with negative exponents, fractional exponents, large exponents, etc. I personally just consider exponentiation to be a complex mathematical function, not your everyday operator.
When I was implementing this functionality for rational numbers (for my library Rationals), I wrote it as a static function Rational.Pow
with an integer exponent and it didn't feel to me like I am missing an operator.
It's just my personal opinion though.
from csharplang.
Now your proposal is too limited for the sake of pow operator. In the real case I think when we require intensive math operation to the point that we need **
it's more likely that we are dealing with mostly real number, not integer
And because we introduce **
while there were already many language have these same operator. I think people would expect it to have as similar behaviour as all other language, such as F#
Also for the sake of same pattern to other arithmetic operator. Maybe I was thinking too much. It should just be the same as *
that, it will just upcast to the largest input number involve to be it's return type, and so the programmer has to choose the type of number by themselves when use **
Just so that 10 ** 10
is overflow exception and might just error in runtime. But 10l ** 10
or 10 ** 10l
just return long
and 10 ** 10f
just return float
10 ** -1
just being 0
and 10 ** -1f
just being 0.1f
from csharplang.
The obvious (although probably very difficult) option would be to allow the definition of custom operators, as in F#... Then, if you want to define the following, you could:
public static long operator ** (int value1, int value2) => Math.Pow(value1, value2);
And then you could deal with the ifs and buts and maybes that crop up in your code...
But we can dream, right?
from csharplang.
@tompazourek - That's a very interesting library, you'll certainly have deep insights into this are.
@Thaina - Yes it is limited but then so is the existing Math.Pow
(limited to double
arguments and return type).
Recall that I'm particularly interested in being able to define constants via expressions of type:
public const long SCALE = 10 ** 3;
public const long MAPPER = 2 ** 6;
and so on. This is often very expressive when there are patters in the values and make it easier to read some kinds of code.
This is not possible today but the prospect of introducing some support for ** brings this within reach.
Having said that it should also be possible to leverage a library like @tompazourek has created. That could be used at runtime and compile time because it is a static method designed to have referential integrity.
Unfortunately it seems unlikely we'll see the ability to have the compiler routinely use static functions that have referential integrity because the necessary basis just isn't there.
Besides as explained by others above exponentiation today is platform specific in the sense that Math.Pow relies in the C runtime library and the compiler can't do that because the C runtime the compiler might use could differ from the C runtime that the code itself may later run against.
I suppose that dotnet/roslyn#7561 could be reopened and given a restricted scope too, for example it could be implemented so that a method is pure if and only if it refers only to it's arguments and other constants or pure methods.
So any method that never refers to external or internal state could be tagged as "pure".
Actually the current issue for "pure" is here.
from csharplang.
Replying to @tompazourek
To me, it feels more like a sibling to functions like Sqrt and Log.
When a full numeric tower is available, I would consider Sqrt
to be a special case of exponentiation, not so much a sibling.
There are all these cases with negative exponents, fractional exponents, large exponents, etc.
My library Symbolism also implements arbitrary precision rational numbers (uses BigInteger
underneath).
Loading up Symbolism into C# interactive:
> #r "Symbolism.dll"
> using Symbolism;
Rational raised to integer power:
> (Integer) 1 / 2 ^ 2
[1/4]
(Note that ^
is overloaded in Symbolism to indicate exponentiation. The precedence of ^
is low so parenthesis are not needed in that example.)
Integer raised to fractional power:
> (4 ^ (Integer) 1 / 3)
[4 ^ 1/3]
Large exponent:
> ((Integer) 2 ^ 500)
[3273390607896141870013189696827599152216642046043064789483291368096133796404674554883270092325904157150886684127560071009217256545885393053328527589376]
When a full numeric tower is available, the special cases that you mentioned make sense and have straightforward implementations.
from csharplang.
@dharmatech Can you explain what you'd consider a full numeric tower? Maybe some links?
from csharplang.
Can you explain what you'd consider a full numeric tower? Maybe some links?
Another example of a math library providing a numeric tower; the ginac computer algebra library for C++ uses the CLN library which provides their their numeric tower:
Number
cl_number
<cln/number.h>
|
|
Real or complex number
cl_N
<cln/complex.h>
|
|
Real number
cl_R
<cln/real.h>
|
+-------------------+-------------------+
| |
Rational number Floating-point number
cl_RA cl_F
<cln/rational.h> <cln/float.h>
| |
| +--------------+--------------+--------------+
Integer | | | |
cl_I Short-Float Single-Float Double-Float Long-Float
<cln/integer.h> cl_SF cl_FF cl_DF cl_LF
<cln/sfloat.h> <cln/ffloat.h> <cln/dfloat.h> <cln/lfloat.h>
from csharplang.
If a community member wants to contribute here, we need a proposal that specifies the exact symbol and precedence for the operator. As an example, something like https://github.com/dotnet/csharplang/blob/master/proposals/csharp-8.0/null-coalescing-assignment.md that details the changes necessary to support the new operator.
from csharplang.
Regarding precedence,
I think aligning with VB and reusing the operator precedence and code generation would be desirable here.
from csharplang.
Just noting here that neither
^^
and*^
can be used, much like*
, due to the existence of^
as both a binary and a preceding unary operator (indexing from the end). This means we have to either consider a completely unrelated symbol to denote exponentation, or use a 3-symbol operator like:
**^
^**
*^*
None of those can cause syntactic ambiguity yet, but
^**
could prohibit usage of the^
operator after an expression for whatever purpose it could be reserved for, causing the ambiguity between(a^) * (*b)
and(a) (^**) (b)
(parentheses used for grouping; actual syntax would be invalid).Speaking of the above, parenthesizing the operators for grouping is another valid solution, which would allow for extending the
**
operator to supporting higher hyperoperators by concatenating*
s together (***
for power towers,****
for power tower towers, etc.). In this case, exponentation would be denoted asa (**) b
, resolving any syntactic ambiguities.
I wonder why no separator was required for stuff like this:
int data = 3;
var p = &data;
var x = &p;
var r = 9***x;
That flexible syntax, though nice and terse, makes it impossible to ever create a new tokens like ** or ***, because a sequence of unseparated * is always regarded as a succession of single * tokens, deferences. The above is treated identically to:
int data = 3;
var p = &data;
var x = &p;
var r = 9 * * * x;
Contrast that with this:
var five = 5;
number = + + five;
number = ++ five;
Here + and ++ are different, the latter is not treated as + + but in the case of dereferencing ** is treated the same as * *.
We could create a new token +++ but not ***.
This can never change of course, this is deeply entrenched in the language now but might be something to learn from.
from csharplang.
This can never change of course, this is deeply entrenched in the language now but might be something to learn from.
It definitely could change. We have the flexibility to change things. Where it would be matter would be if there was code that could legally mean both. In this case, that would not be true. As 9 could not be raised to the power of a pointer, it would be fine to make this work.
from csharplang.
I wonder why no separator was required for stuff like this:
Because it would not be a problem to solve this in the future. In general we only require whitespace based on general 'max consumption' rules normally used in lexical analysis. In this case, there's no concern about *
being consumed into anythign else. So we dont' need anything else to go between the tokens. Requiring whitespace would be onerous.
from csharplang.
I wonder why no separator was required for stuff like this:
Because it would not be a problem to solve this in the future. In general we only require whitespace based on general 'max consumption' rules normally used in lexical analysis. In this case, there's no concern about
*
being consumed into anythign else. So we dont' need anything else to go between the tokens. Requiring whitespace would be onerous.
Well clearly whitespace with + was not considered onerous and + + is distinct from ++.
Besides typically a tokenizer can tokenize based purely on character sequences, here that seems to not be the case.
number = 9 ** X;
So here, would the lexical analyzer return a single ** token or two * tokens? It can't decide it seems, not without some additional information normally not available until the parsing stage.
from csharplang.
Well clearly whitespace with + was not considered onerous and + + is distinct from ++.
Because we shipped with a ++
operator. If we didn't, it would have worked the same way. There's been no need to do the same with **
because taht hasn't shipped. If it did, we'd address appropriately. We have precedence for thsi (no pun intended) as we've already done it in teh past.
from csharplang.
Without disambiguation on +
and ++
, then x++y
could be interpreted as Add(x, UnaryPlus(y))
(x + (+y)
) or possibly several other patterns.
*
I think is interesting because it also means the dereference operation and so the following is already valid code:
public unsafe int M(int x, int* y) {
return x**y; // same as x ** y; x** y; x **y; x * * y; etc
}
It is interpreted as Multiply(x, Dereference(y))
(x * (*y)
). It would, at least to me, be slightly problematic for Int32 ** Int32
to mean Exponent(x, y)
but Int32 ** Pointer<Int32>
to mean Multiply(x, Dereference(y))
(x * (*y)
)
from csharplang.
I don't see **
or ***
being interesting. We would just make it a new operator. And that new operator would mean the following: If i have pointers on the right, then deref (as raising to the power of a pointer doesn't seem sensible). Otherwise, lookup exponentiation operator.
Alternatively, we could always just lookup exponentiation, and if we find something viable, use it. If not, fall back to prior logic. either approach seems like it be fine. I honeslty doubt any change in behavior would ever occur. And, if we were worried about that, or found a case where it would, we could just have it use existing semantics if possible, and new semantics if not.
from csharplang.
Besides typically a tokenizer can tokenize based purely on character sequences, here that seems to not be the case.
Our tokenizer and parser are implementation details. They are a means to an end. They do not normally force the language's hand. The language is defined however it wants, and then the impl does what is necessary to support that.
In this case, we can simply define that we have this operator (and optionally rules for if there's any sort of potential ambiguity). We already have this well understood as we had to do much more involved stuff for things like 'generics'. that was much more involved impl-wise, but wasn't really a big deal either. This lang feature would be much more trivial to handle.
from csharplang.
More in general (and I believe I've commented on similar proposal before) I'm still not convinced of the overall value here:
I agree with this. i think it's solvable, but i also think this is not really something i think is worth investing into.
from csharplang.
The only thoughts I had here was that it would be neat to be able to use exponentiation when initializing constants. Often powers of 10 and powers of 2 are needed and being able to express that as an exponentiation would be neat. One can't use a function call to to init const variables.
However since Math.Pow(<numeric-constant>, <numeric-constant>)
is itself constant perhaps there's a case for having the compiler evaluate the method call at runtime and embed the result into the code? That's common optimization I've seen in some languages/compilers.
private const double Rate = Math.Pow(2, 6); // always 64 no matter when it's evaluated
today we get a compile diagnostic, an error. Perhaps several Math
functions could be treated that way, Sqrt
, Sin
and many more could be evaluated during compile time.
I guess there are cases where despite the args being constants the compiler can't know or assume the result is also always constant.
So this in turn might need an attribute [FoldableResult]
on the method, then the compiler could rely on that to tell it it's safe to do the constant substitution, if that attribute's present and the args are all compile time constants, then it's safe to optimize it away.
C# 11.0 perhaps?...
from csharplang.
from csharplang.
Part of what makes C# C#
is that it is a generalist language. It doesn't strive to be the best particular language in all domains. Math-focused is one domain, of many, that it can play in. However, it doesn't strive to be the ideal math language out there. This is primarily because there's genuinely no end in terms of what would be needed in order to play well there. Yes, Python (no need to avoid the name) may be preferred by some in this space. However, python itself is just one of many popular languages here (like Matlab, R, Wolfram, Idris, Julia, etc.). Attempting to ape the feature sets of those that make them desirable is not only a significant investment, but also a significant departure of what C# strives to be.
Put another way. Adding exponentiation isn't going to be the feature that substantively moves the dial here (IMO). So we should either commit to 'math oriented' being a goal of hte language (with a broad look at the future direction and what that would mean), or we should take it as what it is, and not just add a one-off feature here and there because it's an annoyance to a specific group.
from csharplang.
After reading some of the devs chime in regarding the implementation challenges involved I do have to say that I'm quite sympathetic to their points of view. It definitely should only be undertaken if it's seen as worth the added implementation complexity and overall effort.
I just wanted to get the feature on the radar for discussion and I do appreciate the time everyone has spent so far digging into the subtleties involved. (I've learned a lot from reading the comments.)
from csharplang.
why not collect a list of potential improvements to make C# more math-friendly, be it an operator here, or some construct there, or on the BCL side, some math functionality in classes, etc.; and then prioritize those and tackle 1 or 2 every version.
Regarding other math oriented features on the BCL side, it'd be nice to see a rational number library there someday.
from csharplang.
There isn't consensus on this, and you'll have the spectrum of people going:
...
This probably applies to any C# feature set, and I think that's normal to have this spectrum of opinions. I agree that we shouldn't listen to '3' all the time.
So, IMO, we already do this. It's just that that genuinely may mean that a particular feature (like this one) just may not be relevant. It might be, for example, that we extend things like operators to work on tuples/arrays/etc. as that may be more pressing and much more painful to not have.
So even if we go this route, I would say that you should not expect that that would mean that exponentiation would ever meet the bar as needing direct lang syntax.
As listed above, it certainly looks like progress has been made, at least on the .NET side - and I apologize for not being fully aware of the extent of the work in this area - as I said, I don't tackle math projects almost at all.
Having said that, given how many other languages have an operator for exponents, and that it's a very common notation in mathematical equations/formulas, it does seem like a glaring omission.
Regarding the issues with **
conflicting with pointers, we could go with ^^
instead; it sidesteps a lot of issues and makes it a straightforward addition.
Regarding constants, (playing devil's advocate here) something like "deterministic functions" (for which there is a proposal somewhere) could solve a lot of those challenges, not just exponents.
from csharplang.
Related Issues (20)
- [Proposal]: Relax `Add` requirement for collection expression conversions to types implementing `IEnumerable` HOT 2
- [Proposal]: Proposal for Allowing Single-Element Tuples in Type Definitions HOT 2
- [Proposal]: Params collections and older language versions HOT 1
- [Proposal]: Edit speclets to distinguish features already delivered from potential future enhancements HOT 3
- [Proposal]: `readonly` parameters in primary constructors for non-record types HOT 7
- [Issue]: Generic Type Specialization Not Working in C# HOT 38
- [Proposal]: AAAAAAAAAAAAAAAAAAAA
- Open questions for `field` and `value` as contextual keywords HOT 2
- Add collection literal support for `Memory<T>` and `ReadOnlyMemory<T>`. HOT 18
- Unexpected compiler behavior with records and implicit operators HOT 1
- YaoJunFeng
- Invalid implicit conversion from long to int HOT 6
- [Proposal]: Extending patterns to "as" HOT 28
- Proposal: Searched switch statement HOT 2
- [Proposal]: Allow `with` keyword for classes containing constructor expecting itself HOT 1
- [Proposal]: [Allow Custom Implicit Conversion from Struct to Nullable Struct] HOT 1
- [Proposal]: Better conversion from collection expression with `ReadOnlySpan<T>` overloads
- [Proposal]: `params in` parameters HOT 9
- [API Proposal]: Collection Expressions and ```String.Empty```
- [] matches string and byte[] in overload resolution, but it can't be a string HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from csharplang.