estatico / scala-newtype Goto Github PK
View Code? Open in Web Editor NEWNewTypes for Scala with no runtime overhead
License: Apache License 2.0
NewTypes for Scala with no runtime overhead
License: Apache License 2.0
I suppose the companion objects aren't working as expected
when they have a type hierarchy.
Consider a simple example:
abstract class AbstractObjectCompanion[T] {
def apply(src: Int): T
implicit class Ops(t: T) {
def print = t.toString
}
}
import io.estatico.newtype.macros.newtype
package object some {
@newtype class MyInt(val i: Int)
object MyInt extends AbstractObjectCompanion[MyInt] {
override def apply(src: Int): MyInt = new MyInt(src)
}
}
... does not compile:
illegal cyclic reference involving type MyInt
object MyInt extends AbstractObjectCompanion[MyInt] {
But it compiles without @newtype
OR without AbstractObjectCompanion.
hi!
I was just wondering if you did anything more on the deriving support?
Also you didn't raise a merge request against https://gitlab.com/fommil/scalaz-deriving/ so I can't see our work ๐
Given:
trait Foo
trait Bar extends Foo
why wouldn't
@newtype class NFoo(val internal: Foo)
@newtype class NBar(override val internal: Bar) extends NFoo(internal)
be valid?
@alexknvl pointed out that it's possible to encode newtypes in such a way that casting Arrays with asInstanceOf
will work (which means Coercible can work too).
Here's a simple adaptation from his solution to demonstrate a failing test case.
object Example {
class Foo[A](val a: Array[A])
val foo = new Foo(Array(1, 2, 3))
def subst[F[_], T](fa: F[Int]): F[T] = fa.asInstanceOf[F[T]]
type Good = Good.Type
object Good {
type Base <: Any
trait Tag extends Any
type Type <: Base with Tag
}
def good() = println(subst[Foo, Good](foo).a.head)
@newtype case class Bad(value: Int)
def bad() = println(subst[Foo, Bad](foo).a.head)
def main(args: Array[String]): Unit = {
good()
bad()
}
}
If we try this:
@newsubtype final case class Foo(value: Integer)
implicitly[Null <:< Foo]
Then it fails to compile with:
[error] Cannot prove that Null <:< web.base.react.package.Foo.
[error] implicitly[Null <:< Foo]
[error] ^
Would it be possible that if Repr <: AnyRef
then Type
becomes:
type Type >: Null <: Base with Tag
It seems that encoding newtypes with a "normal" type alias means that scalac can expand it at will. We need to change the encoding from
type Type[..] = Base with Tag[..]
to
type Type[..] <: Base with Tag[..]
See scala/bug#10750
I finally found this lib which seems far better than alternatives https://github.com/alexknvl/newtypes , https://github.com/vitorsvieira/dilate , https://github.com/rudogma/scala-supertagged โ but i found it accidentally even though I searched actively for ways to get newtypes in scala, adding a newtype
, tagged
, tagged-types
tags might make it easier to discover the lib
On Scala 2.13 with -Xsource:2.14
compiler option, newtype macro gives the following warning
Auto-application to `()` is deprecated. Supply the empty argument list `()` explicitly to invoke method hashCode,
or remove the empty argument list from its definition (Java-defined methods are exempt).
In Scala 3, an unapplied method like this will be eta-expanded into a function.
It makes newtypes unusable with both this option and -Xfatal-warnings
enabled
I needed a new sub-type / tagged type for a value class. It had to be a sub-type because I needed to use it in all the places where the base type could be used but perhaps more importantly I needed all the implicit conversions to be found from its companion object.
The problem with @newsubtype
is that it doesn't support value classes. One reason is because the Ops$newtype
is a value class which cannot wrap another user-defined value class.
I tried doing something more like what Shapeless does but then I run into a bunch of ClassCastException
s. I initially reported that in scala-js/scala-js#4778 as I thought it was a Scala.js specific issue but that turns out to be untrue. I found a bunch of related Shapeless issues (see that issue for links).
I started wondering how it was that @newtype
avoided these ClassCastException
s (and as hinted by Miles in some of his comments that Shapeless 3 may change Tagged
back to how it was). It seems that the structural type is the key here.
We of course need the type we are extending somewhere in Type
for it to be a subtype but it can't be in Base
.
This encoding seems to do the trick:
import scala.language.implicitConversions
object Main {
final class KeyAddingStage(private val args: Array[Any]) extends AnyVal
object KeyAddingStage {
implicit def build(stage: KeyAddingStage): String = stage.toString
}
type RenderedProps[Props] = RenderedProps.Type[Props]
object RenderedProps {
type Base = {
type __RenderedProps__newtype
}
trait Tag[Props] extends Any
type Type[Props] <: Base with KeyAddingStage with Tag[Props]
def apply[Props](stage: KeyAddingStage): RenderedProps[Props] = stage.asInstanceOf[RenderedProps[Props]]
}
object Name {
case class Props(name: String)
def component(props: Props): KeyAddingStage = new KeyAddingStage(
Array(
props.asInstanceOf[Any]
)
)
def apply(name: String): RenderedProps[Props] = RenderedProps(component(Props(name)))
}
def main(args: Array[String]): Unit = {
val first: RenderedProps[Name.Props] = Name("Jason")
val firstStage: KeyAddingStage = first
val str: String = first
println(first == firstStage)
val props: Seq[RenderedProps[Name.Props]] = Seq(first)
val propsHead: RenderedProps[Name.Props] = props.head
println(firstStage == propsHead)
}
}
Any thoughts on adding something like this so that we can have @newsubtype
support for value classes?
ClassTags are used by scalac during type-based pattern matching. This is a problem for newtypes (but not newsubtypes) since their ClassTag runtime class is Object
. As such, we are permitting users via our "safe" API to do unsafe things without it being obvious that what they are doing will definitely result in a runtime exception.
scala> import io.estatico.newtype.macros._, io.estatico.newtype.ops._
scala> @newtype case class Foo(x: String)
scala> (1: Any) match { case x: Foo => x ; case _ => Foo("nope") }
res0: Foo = 1
scala> res0.coerce[String]
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
... 38 elided
I think the solution for now is to remove ClassTag instances altogether. The only reason I think they're useful is for constructing Arrays, but I think this is the wrong solution. I have an experimental (and incomplete) branch for a different way of handling Arrays here (via an AsArray
type class). I'm looking to try to use this to resolve #10 in a type safe way.
In the meantime, I think it's best to remove the ClassTag instances to prevent unsafe code from happening by accident.
Also see my original point about this with regard to the unapply
method here.
I'm making a web app and using newtypes to for type-safe IDs for different model types.
As there are quite a few model types, I tried to move type code into a trait that can be mixed into companion object:
trait OwnIdType {
@newtype case class ID(toInt: Int)
object ID {
// Circe things
implicit val toJson: Encoder[ID] = deriving
implicit val fromJson: Decoder[ID] = deriving
}
}
That didn't work, however, telling me that fields can only be used if the newtype is defined inside an object
Ultimately I wrote case class boilerplate myself:
trait OwnIdType {
@newtype class ID(underlying: Int)
object ID {
def apply(value: Int): ID = value.coerce
implicit class Ops(val id: ID) {
def toInt: Int = id.coerce
}
implicit val toJson: Encoder[ID] = deriving
implicit val fromJson: Decoder[ID] = deriving
}
}
It compiles and works, and the only significant difference is that Ops
class cannot extend AnyVal
.
Is it possible to support @newtype case class
inside traits by dropping extends AnyVal
on ops class?
hi @carymrobbins I am wondering if you would consider adding more maintainers to this project? I myself will be more than happy to help.
In some use cases, for some type classes I just want to provide instances for all new types based on the instances of their base class. E.g a circe Json encoder (or the Format
in play json).
The solution I have now is like the following, but it's tied to the legacy encoding and too coupled to the implementation detail:
trait BaseAutoDerive[F[_]] extends LowerPriorityAudoDerive[F] {
implicit def newTypeDerive[Base, Repr, Tag](implicit ev: F[Repr]): F[BaseNewType.Aux[Base, Tag, Repr]] =
ev.asInstanceOf[F[BaseNewType.Aux[Base, Tag, Repr]]]
}
trait LowerPriorityAudoDerive[F[_]] {
implicit def newTypeDeriveForRepr_[Tag, Repr_](implicit ev: F[Repr_]):
F[BaseNewType.Aux[AnyRef{type Repr = Repr_}, Tag, Repr_]] =
ev.asInstanceOf[F[BaseNewType.Aux[AnyRef{type Repr = Repr_}, Tag, Repr_]]]
}
Then you can do
object autoFormatDerive extends BaseAutoDerive[Format]
import autoFormatDerive._
Note that a simpler Coercible
solution doesn't work, namely the following doesnt resolve the implicts
implicit def coercibleEq[A, B](implicit ev: Coercible[B, A], B: Eq[B]): Eq[A] =
B.asInstanceOf[Eq[A]]
Hi! Thanks for a wonderful library.
We're hitting an interesting issue:
@newtype case class Demo(value: Int) {
def +(another: Demo): Demo = ???
}
def demo(d: Demo) = d + d
^ type mismatch;
found : (...).Demo
(which expands to) (...).Demo.Type
required: String
If I just say d +
, I get missing argument list for method + in class any2stringadd
. As far as I could find out, that method gets special treatment and can't be unimported.
I took a look at the implementation of newtypes and as far as I could tell methods from the class are moved to an implicit class next to it, to which a conversion called Demo.Ops$newtype
is applied - when I apply it manually, or import it (import Demo._
or by exact name) it compiles as expected. I assume any2stringadd
just has higher precedence because it's imported.
Is there something scala-newtype can do to allow this name in methods on newtypes?
I'm starting to use more and more of this library. In particular, newtypes are quite useful for defining custom typeclass instances:
@newtype case class FirstOf[A](value: A)
object FirstOf {
implicit def semigroup[A]: Semigroup[A] = Semigroup.instance((a, _) => a)
}
It would be really nice if for these cases unapply
would also be generated. This comes in handy in chains involving foldMap, e.g.
list
.foldMap(person => Map(person.name -> FirstOf(person.age))
.map { case (name, FirstOf(age)) => ??? } // no need to use `.value` manually
Hello ๐
I have a very simple case and I couldn't find documentation on how to deal with this ๐คทโโ๏ธ
I've declared a new type like this:
@newtype final case class Id(value: String)
@newtype final case class ExternalId(value: String)
Later in the code I finish up with a map mapping: Map[Id, ExternalId]
. But when I need to collect it's keys/values to an array I get compilation errors:
val myIds = mapping.keys.toArray
val externalIds = mapping.values.toArray
Error:
No ClassTag available for ...Id
No ClassTag available for ...ExternalId
How is this supposed to be handled. Are newtypes incompatible with arrays because of generics?
The current encoding allows for some unsafe type ascriptions. While this would basically never happen in a real world scenario, we should still look into improving the encoding.
Here's an example of the problem. I've abridged the debug output for simplicity.
scala> @newtype(debug = true) case class Foo(x: String)
Expanded @newtype Foo:
{
type Foo = Foo.Type;
abstract trait Foo$Types extends scala.AnyRef {
type Repr = String;
type Base = _root_.scala.Any { type Foo$newtype };
abstract trait Tag extends _root_.scala.Any;
type Type <: Base with Tag
};
object Foo extends scala.AnyRef with Foo$Types { .. }
}
defined type alias Foo
defined trait Foo$Types
defined object Foo
scala> Foo("a"): Foo.Tag
java.lang.ClassCastException: java.lang.String cannot be cast to Foo$Types$Tag
The main reason for the Tag
trait is to anchor the companion so it's in the implicit search path. I've been experimenting with refinements to see if that could help but so far I've been unable to get implicit resolution working without it.
Sorry, this isn't an issue as such, I was just looking for more information on how newtype works. The README says something like this is generated:
package object types {
type WidgetId = WidgetId.Type
object WidgetId {
type Repr = Int
type Base = { type WidgetId$newtype }
trait Tag
type Type <: Base with Tag
def apply(x: Int): WidgetId = x.asInstanceOf[WidgetId]
implicit final class Ops$newtype(val $this$: Type) extends AnyVal {
def toInt: Int = $this$.asInstanceOf[Int]
}
}
}
I get the basic idea that you use macros to generate a value class but I wasn't sure why so many intermediate types are defined or what type Base = { type WidgetId$newtype }
, which looks abstract, did?
Any more info would be much appreciated, thanks!!!
The Coercible
instances currently generated by the @newtype
macro are always publicly available in implicit scope. I think this makes sense when defining a newtype as a case class
since a standard apply
method will be generated, but when defining one as a class
with a custom apply
method, it allows external code to bypass any validation logic in that method. For example
// types.scala
package object types {
@newtype class PositiveInt(i: Int)
object PositiveInt {
def apply(i: Int): Option[PositiveInt] = if (i > 0) Some(i.coerce[PositiveInt]) else None
}
}
// test.scala -- this compiles but ideally it wouldn't
-1.coerce[types.PositiveInt]
Would it be possible to make the Coercible
instances for a class
only visible in implicit scope in the companion object? Or if that seems like too broad of a change, perhaps the logic could only apply when the class
constructor is explicitly marked as private, e.g. @newtype class PositiveInt private (i: Int)
?
Thank you for all your work on this library!
I have the following code:
package object stuff {
@newtype case class Thing(underlying: Int)
}
In scala 2.12.x the following warning is issued (making -Xfatal-warning impossible):
[warn] package.scala:10: it is not recommended to define classes/objects inside of package objects.
[warn] If possible, define trait MetricActorRef__Types in package metrics instead.
[warn] @newtype case class MetricActorRef(underlying: ActorRef)
[warn] ^
This warning happens if I use any scala-newtype version > 0.2.1
(that's the last version that works without the warning).
I am able to work around the issue by using https://github.com/ghik/silencer with the pathFilters pointing to the file in question (the @silent annotation does not work).
Example:
case class Type(name: String)
@newtype case class Foo(value: List[Type])
val value: List[Type] = List(Type("abc"))
Foo(value)
The code does not compile due to the following error:
type mismatch;
found : List[Type]
required: List[Foo.Type]
The simplest solution is to rename all type aliases to avoid the possibility of name collision (like prefixing them with $
).
type $Base = ...
type $Repr = ...
type $Type = ...
type $Tag = ...
Currently, as a workaround, the user can create an alias (if changing the name isn't an option), and the code would work as expected:
type TType = Type
@newtype case class Foo(value: List[TType])
The README.md compares this library to Haskell's newtype
and to Tagged types. However, more crucially, it doesn't mention how this is any different/better than simply using case class Thing(value: String) extends AnyVal
.
From my understand this is an alternative to extends AnyVal
, hence this info is crucial.
it would be awesom if the NewType and NewSubType would also behave respectively when applied to isInstanceOf[_]
and case _:Type =>
while a NewType is indeed not recognized for function arguments
import io.estatico.newtype.NewType
object Point extends NewType.Default[(Int, Int)]
val p = Point((1,2))
def add(t:(Int, Int)): Int = t._1 + t._2
add(p) // will raise an error
The following does not work as hoped for
p.isInstanceOf[(_, _)] // returns <true>, however we would like to have <false>
p match {
case p: (_, _) => "bad"
case _ => "good"
} // returns "bad"
Is this an underlying systematic issue or can this be adapted to fit the NewType / NewSubType distinction?
any interest in adding scala.js support?
Hi. Newtype name is always equal to "Type" in compiler errors.
Example is Either[Type, Type] where it has to be Either[UserId, UserUid].
Is it possible to get proper names?
Currently, for newtypes we generate a Coercible[O, N]
instance where O
is the original type and N
is the newtype. While this is perfectly fine, we go a step further and generate a Coercible[F[O], F[N]]
instance for any F[_]
. This is where we get into trouble. There are cases where this shouldn't be permitted due to the nature of the data structure we're dealing with. For example, let's look at how this would work with dogs.Set which relies on an implicit Order
instance for its operations -
import cats.instances.int._
import cats.Order
import io.estatico.newtype.ops._
import io.estatico.newtype.macros.newtype
// Like Int except ordered in reverse.
@newtype case class RevInt(value: Int)
object RevInt {
implicit val order: Order[RevInt] =
Order.from((x, y) => -Order[Int].compare(x.value, y.value))
}
// Build a dogs.Set[Int]
println(dogs.Set(1, 2, 3))
// Set(1,2,3)
// Build a dogs.Set[RevInt]
println(dogs.Set(RevInt(1), RevInt(2), RevInt(3)))
// Set(3,2,1)
// Build a dogs.Set[Int], coerce it to dogs.Set[RevInt], and add an element
println(dogs.Set(1, 2).coerce[dogs.Set[RevInt]] + RevInt(3))
// Set(3,1,2)
One quick and dirty way to deal with this would be to introduce type roles via a type class.
trait TypeRole[A] {
type Role
}
object TypeRole {
def mk[A, R]: TypeRole[A] { type Role = R } =
_instance.asInstanceOf[TypeRole[A] { type Role = R }]
private val _instance = new TypeRole[Nothing] {}
type Nominal[A] = TypeRole[A] { type Role = types.Nominal }
type Representational[A] = TypeRole[A] { type Role = types.Representational }
object types {
sealed trait Representational
sealed trait Nominal
}
}
Then we'd define this Coercible instance based on the type role -
implicit def reprF[F[_], A, B](
implicit ev: TypeRole.Representational[F[A]]
): Coercible[F[A], F[B]] = Coercible.unsafe
We then need to define type role instances -
implicit def typeRoleScalaSet[A]: TypeRole.Representational[Set[A]] = TypeRole.mk
implicit def typeRoleDogSet[A]: TypeRole.Nominal[Set[A]] = TypeRole.mk
// Compiles
println(Set(1, 2, 3).coerce[Set[RevInt]])
// Set(1, 2, 3)
// Does not compile now
println(dogs.Set(1, 2, 3).coerce[dogs.Set[RevInt]])
See -
I'd like to do something like the following, which is a fully compilable version of http://degoes.net/articles/effects-without-transformers
But if I change the value class encoding for @newtype
, I get a compile error
[error] stateio.scala:23:49: class type required but stateio.FastState.StateTask.Type[A] found
[error] def from[X](fa: Task[X]) = new StateTask(fa)
[error] ^
import scalaz._, Scalaz._, ioeffect._
import Isomorphism._
import io.estatico.newtype.macros.newtype
object FastState extends SafeApp {
final class StateTask[A](val io: Task[A]) extends AnyVal
object StateTask {
def create[S](initial: S): Task[MonadState[StateTask, S]] =
for {
ref <- IORef(initial)
} yield
new MonadState[StateTask, S] with IsomorphismMonad[StateTask, Task] {
override val G: Monad[Task] = Monad[Task]
override val iso: StateTask <~> Task =
new IsoFunctorTemplate[StateTask, Task] {
def to[X](ga: StateTask[X]) = ga.io
def from[X](fa: Task[X]) = new StateTask(fa)
}
override def get: StateTask[S] = new StateTask(ref.read)
override def put(s: S): StateTask[Unit] =
new StateTask(ref.write(s))
override def init = get
}
}
def program[F[_]](implicit F: MonadState[F, Int]): F[String] =
for {
orig <- F.get
update = orig + 10
_ <- F.put(update)
} yield update.toString
def app: Task[Unit] =
for {
stateMonad <- StateTask.create(10)
output <- program(stateMonad).io
_ <- console.putStrLn(output).widenError[Throwable]
} yield ()
def run(@unused args: List[String]): IO[Void, ExitStatus] =
app.attempt.map(_ => ExitStatus.ExitNow(0))
}
This is only possible with NewSubType
but I think it's still useful.
version 0.4.2.
object Test {
@newsubtype case class VectorPointer(addr: Long)
}
scala> new Array[Test.VectorPointer](10)
<console>:12: error: cannot find class tag for element type Test.VectorPointer
new Array[Test.VectorPointer](10)
Given this reproduction:
import io.estatico.newtype.macros.newsubtype
import scala.scalajs.js.|
object Main extends App {
@newsubtype final case class Foo[A](unwrap: A)
@newsubtype final case class Bar[A](unwrap: A)
def which[A, B](fooOrBar: Foo[A] | Bar[B]) = fooOrBar match {
case _: Foo[_] => "foo"
case _: Bar[_] => "bar"
}
}
How can I avoid this error?
[error] /Users/jason/src/bug-reports/src/main/scala/Main.scala:12:13: abstract type pattern Main.Foo.Type[_] (the underlying of Main.Foo[_]) is unchecked since it is eliminated by erasure
[error] case _: Foo[_] => "foo"
[error] ^
Normally in Scala.js we would have to ascribe it as Any
to do the match but that doesn't seem necessary here for whatever reason. IntelliJ at least still thinks that this is a fruitless type test so the Any
ascription could be cleaner.
I was thinking maybe it has something to do with this comment in #18 although I'm not quite seeing the implications:
Note that when matching on Any compiler warnings will be emitted, so I think that should be enough to clue in users that they're being unsafe.
Is there a workaround, even if it is unsafe?
I often wrap newtypes in newtypes and then I want to access the basetype. Example:
@newtype case class Secret(value: String)
@newtype case class Password(value: Secret)
@newtype case class AdminPassword(value: Password)
val adminPassword: AdminPassword = ???
// Access the basetype
println(adminPassword.value.value.value)
Something like adminPassword.coerce[String]
would be nice, or maybe even adminPassword.underlying
. As Coercible
is a typeclass, I think with the correct derivation it should be possible to get something like it.
Opinions?
Currently, there is no way to get a TypeTag
for a newtype:
@newtype case class WidgetId(toInt: Int)
val widgetId = WidgetId(5)
import scala.reflect.runtime.universe._
val tt = typeTag[WidgetId] // failed with No TypeTag available
WeakTypeTag
works fine:
val wtt = weakTypeTag[WidgetId]
Also, I can get a TypeTag
for the Repr
type:
val repr = typeTag[WidgetId.Repr]
Looks like there is no way to get a TypeTag
for the newtype in the current newtype encoding because newtype's type is abstract, but TypeTag can be summoned only for a concrete type.
About my use case: I'm using doobie and it uses TypeTag
s very extensively for better logging and error reporting.
Since the introduction of newtypes in conjuction with refined I see a big increase in compilation time. Especially in my postgres module. I was using refined before in my postgres module, but not with newtypes. I'm using doobie and SQL/fragment interpolated strings to construct queries. The string interpolator of doobie summons foreach interpolated variable a Put
type class (which is used to convert the variable being interpolated to a JDBC data type).
Here's the code to convert newtypes to Put
and Get
(for reading data from JDBC)
implicit def coerciblePut[N, P](implicit ev: Coercible[Put[P], Put[N]], R: Put[P]): Put[N] = ev(R)
implicit def coercibleGet[N, P](implicit ev: Coercible[Get[P], Get[N]], R: Get[P]): Get[N] = ev(R)
I've included the scalac-profiling aswell: https://gist.github.com/Fristi/363e7fcf8f899e24eae53d42d741fd13
It seems to not have repeeated expansions, but rather unique expansions
I have the following code:
package object stuff {
@newtype case class Thing(underlying: Int)
}
In scala 2.12.x the following warning is issued (making -Xfatal-warning impossible):
[warn] package.scala:10: it is not recommended to define classes/objects inside of package objects.
[warn] If possible, define trait MetricActorRef__Types in package metrics instead.
[warn] @newtype case class MetricActorRef(underlying: ActorRef)
[warn] ^
This warning happens if I use any scala-newtype version > 0.2.1
(that's the last version that works without the warning).
I am able to work around the issue by using https://github.com/ghik/silencer with the pathFilters pointing to the file in question (the @silent annotation does not work).
There's a little less known pattern allowing for high-performance no-allocation unapply
method construction. It's described in this blogpost by Heiko Seeberger.
Do you think it would be possible to actually generate sensible name-based extractors in your macros?
There are use cases when the generation of the Coercible
instances is not required. One example might be when using @newtype
annotation in the internal implementation of a library without bringing a runtime dependency on the Coercible
type to the users of the latter. A possible way could be to add another flag like the ones in here to drive select this behaviour. Something like coercible: Boolean = true
. Thanks.
This doesn't compile due to the use of T
as a type param in the generated deriving
method -
@newtype case class CanDerive[F[_], R, T](value: F[T])
Generates this method -
def deriving[T[_], F[_], R, T](implicit ev: T[Repr[F, R, T]]): T[Type[F, R, T]] = ev.asInstanceOf[T[Type[F, R, T]]]
We should go through the methods and make sure we use unique names, either by suffixing with $
or using something like c.freshName
.
I'd like to propose the following steps:
Currently, there is nothing to prevent you from erroneously casting to/from array types. See this discussion on Gitter for a proposed solution.
Is there a possibility to create a NewType for Seq[A]
?
object
unfortunately takes no typeparameters ...
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.