From 9270e16519cd7f5e0deb83015a8361911396ef70 Mon Sep 17 00:00:00 2001 From: jpconsuegra Date: Sun, 18 Feb 2024 10:41:53 -0500 Subject: [PATCH] Add Lecture 04 (+Code) --- .../04-class-and-enum/code/App/App.csproj | 14 ++ .../04-class-and-enum/code/App/Program.cs | 94 ++++++++ .../2024/04-class-and-enum/code/Sets.sln | 28 +++ .../2024/04-class-and-enum/code/Sets/Set.cs | 150 ++++++++++++ .../04-class-and-enum/code/Sets/Sets.csproj | 9 + .../2024/04-class-and-enum/code/makefile | 2 + .../2024/04-class-and-enum/lecture-04.md | 227 ++++++++++++++++++ 7 files changed, 524 insertions(+) create mode 100755 conferences/2024/04-class-and-enum/code/App/App.csproj create mode 100755 conferences/2024/04-class-and-enum/code/App/Program.cs create mode 100755 conferences/2024/04-class-and-enum/code/Sets.sln create mode 100755 conferences/2024/04-class-and-enum/code/Sets/Set.cs create mode 100755 conferences/2024/04-class-and-enum/code/Sets/Sets.csproj create mode 100755 conferences/2024/04-class-and-enum/code/makefile create mode 100644 conferences/2024/04-class-and-enum/lecture-04.md diff --git a/conferences/2024/04-class-and-enum/code/App/App.csproj b/conferences/2024/04-class-and-enum/code/App/App.csproj new file mode 100755 index 0000000..d99da63 --- /dev/null +++ b/conferences/2024/04-class-and-enum/code/App/App.csproj @@ -0,0 +1,14 @@ + + + + + + + + Exe + net6.0 + enable + enable + + + diff --git a/conferences/2024/04-class-and-enum/code/App/Program.cs b/conferences/2024/04-class-and-enum/code/App/Program.cs new file mode 100755 index 0000000..aefe281 --- /dev/null +++ b/conferences/2024/04-class-and-enum/code/App/Program.cs @@ -0,0 +1,94 @@ +using MatCom.Logic; + + +class Program +{ + static void Main() + { + TestEmptySetHasSizeZero(); + TestSingletonSetHasSizeOne(); + TestContains(); + TestSetRemovesDuplicates(); + + TestUnionOfDisjointSets(); + TestUnionOfSameElements(); + TestUnionOfSameAndDifferentElements(); + + TestIntersection(); + + Console.WriteLine("✅ Everything OK!"); + } + + static void Assert(bool condition, string message = "") + { + if (!condition) + { + throw new Exception(message); + } + } + + static void TestEmptySetHasSizeZero() + { + Set s = new Set(); + Assert(s.Size == 0, "Size should be 0, not " + s.Size); + } + + static void TestSingletonSetHasSizeOne() + { + Set s = new Set(42); + Assert(s.Size == 1, "Size should be 1, not " + s.Size); + } + + static void TestContains() + { + Set s = new Set(1, 2, 3); + + Assert(s.Contains(1), "Should contain 1"); + Assert(s.Contains(2), "Should contain 2"); + Assert(s.Contains(3), "Should contain 3"); + Assert(!s.Contains(4), "Should not contain 4"); + } + + static void TestSetRemovesDuplicates() + { + Set s = new Set(1, 2, 1, 3, 2); + + Assert(s.Size == 3, "Size should be 3, not " + s.Size); + } + + static void TestUnionOfDisjointSets() + { + Set s1 = new Set(1, 2, 3); + Set s2 = new Set(4, 5, 6, 7); + Set s3 = s1.Union(s2); + + Assert(s3.Size == s1.Size + s2.Size, "Should have all of the elements"); + } + + static void TestUnionOfSameElements() + { + Set s1 = new Set(1, 2, 3); + Set s2 = new Set(1, 2, 3); + Set s3 = s1.Union(s2); + + Assert(s3.Size == s1.Size, "Should have exactly one copy of the elements"); + } + + static void TestUnionOfSameAndDifferentElements() + { + Set s1 = new Set(1, 2, 3); + Set s2 = new Set(1, 2, 3, 4); + Set s3 = s1.Union(s2); + + Assert(s3.Size == Math.Max(s1.Size, s2.Size), "Should have exactly one copy of the elements"); + } + + static void TestIntersection() + { + Set s1 = new Set(1, 2, 3, 4, 5); + Set s2 = new Set(2, 4, 6, 8); + Set s3 = s1.Intersection(s2); + + Assert(s3.Size == 2, "Should contain only 2 and 4"); + } +} \ No newline at end of file diff --git a/conferences/2024/04-class-and-enum/code/Sets.sln b/conferences/2024/04-class-and-enum/code/Sets.sln new file mode 100755 index 0000000..1ed0a4c --- /dev/null +++ b/conferences/2024/04-class-and-enum/code/Sets.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sets", "Sets\Sets.csproj", "{FDECD36D-DDE4-45AA-B532-98189C7B2BBF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "App\App.csproj", "{F13681D9-7077-4337-9AC7-DFCAFFF723DF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FDECD36D-DDE4-45AA-B532-98189C7B2BBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FDECD36D-DDE4-45AA-B532-98189C7B2BBF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FDECD36D-DDE4-45AA-B532-98189C7B2BBF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FDECD36D-DDE4-45AA-B532-98189C7B2BBF}.Release|Any CPU.Build.0 = Release|Any CPU + {F13681D9-7077-4337-9AC7-DFCAFFF723DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F13681D9-7077-4337-9AC7-DFCAFFF723DF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F13681D9-7077-4337-9AC7-DFCAFFF723DF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F13681D9-7077-4337-9AC7-DFCAFFF723DF}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/conferences/2024/04-class-and-enum/code/Sets/Set.cs b/conferences/2024/04-class-and-enum/code/Sets/Set.cs new file mode 100755 index 0000000..e57b277 --- /dev/null +++ b/conferences/2024/04-class-and-enum/code/Sets/Set.cs @@ -0,0 +1,150 @@ +namespace MatCom.Logic; + +public class Set +{ + private int[] elements; + + // Constructor privado que solo puedo llamar desde esta clase, + // por lo tanto según el uso, a veces puedo confiar en que los + // elementos no estén repetidos, y me ahorro tener que hacer esa + // verificación 2 veces. + private Set(int[] elements, bool safe) + { + if (!safe) + { + elements = Unique(elements); + } + + this.elements = elements; + } + + // Constructor público que llamarán los usuarios de la biblioteca, + // por definición no puedo confiar en la entrada. + public Set(params int[] elements) + { + this.elements = Unique(elements); + } + + public int Size + { + get { return this.elements.Length; } + } + + public bool Contains(int x) + { + for (int i = 0; i < this.elements.Length; i++) + { + if (this.elements[i] == x) + { + return true; + } + } + + return false; + } + + public Set Union(Set other) + { + int[] union = new int[this.Size + other.Size]; + int total = 0; + + // Como cada conjunto no tiene elementos repetidos, + // podemos poner con total seguridad los del conjunto actual + for (int i = 0; i < this.Size; i++) + { + union[total++] = this.elements[i]; + } + + // Ahora ponemos los del otro conjunto, que algunos estarán repetidos + for (int i = 0; i < other.Size; i++) + { + union[total++] = other.elements[i]; + } + + return new Set(union); + } + + public Set Intersection(Set other) + { + int[] intersection = new int[Math.Min(this.Size, other.Size)]; + int total = 0; + + // Por cada elemento del conjunto actual, lo ponemos si y solo si + // también está en el otro conjunto + // Usaremos un ciclo foreach porque no nos interesa el índice + foreach (int x in this.elements) + { + if (other.Contains(x)) + { + intersection[total++] = x; + } + } + + // Finalmente devolvemos un Set nuevo pero solo con la cantidad + // de elementos necesarios, usando el constructor privado + return new Set(Resize(intersection, total), true); + } + + #region Métodos auxiliares + + private static int[] Unique(int[] elements) + { + int[] temp = new int[elements.Length]; + int total = 0; + + // Poner en temp solamente aquellos elementos nuevos + for (int i = 0; i < elements.Length; i++) + { + if (!Find(elements[i], temp, total)) + { + temp[total++] = elements[i]; + } + } + + return Resize(temp, total); + } + + private static int[] Resize(int[] array, int newSize) + { + // Crear un nuevo array con la cantidad justa de elementos + int[] result = new int[newSize]; + + for (int i = 0; i < newSize; i++) + { + result[i] = array[i]; + } + + return result; + } + + private static bool Find(int x, int[] array, int length) + { + for (int i = 0; i < length; i++) + { + if (array[i] == x) + { + return true; + } + } + + return false; + } + + #endregion +} + +// EJERCICIOS + +// 1) Adicione el método de instancia `Set Difference(Set other)` que devuelve el conjunto diferencia entre el +// conjunto actual y `other`, e implemente los tests que considere necesarios para evaluarlo. + +// 2) Adicione un método de instancia `bool Equivalent(Set other)` que devuelve `true` si y solo si ambos +// conjuntos tienen exactamente los mismos elementos, e implemente los tests necesarios. +// Recuerde que los conjuntos no tienen orden intrínseco. + +// 3) Adicione un método de instancia `string PrettyPrint()` que devuelve un `string` con los elementos del +// conjunto, en la notación usual de lógica, e.j. `{ 1, 3, 2, 9, 0 }`. Los elementos pueden estar en cualquier orden. +// Hint: Utilice la clase `StringBuilder` para construir un `string` de forma más eficiente que con el operador `+`. + +// 4) Modifique el método `Union` para que no necesite llamar al constructor público, sino que garantice directamente +// que los elementos no están duplicados y por tanto se pueda llamar al constructor privado. diff --git a/conferences/2024/04-class-and-enum/code/Sets/Sets.csproj b/conferences/2024/04-class-and-enum/code/Sets/Sets.csproj new file mode 100755 index 0000000..4658cbf --- /dev/null +++ b/conferences/2024/04-class-and-enum/code/Sets/Sets.csproj @@ -0,0 +1,9 @@ + + + + net7.0 + enable + enable + + + diff --git a/conferences/2024/04-class-and-enum/code/makefile b/conferences/2024/04-class-and-enum/code/makefile new file mode 100755 index 0000000..8caca91 --- /dev/null +++ b/conferences/2024/04-class-and-enum/code/makefile @@ -0,0 +1,2 @@ +test: + dotnet run --project App diff --git a/conferences/2024/04-class-and-enum/lecture-04.md b/conferences/2024/04-class-and-enum/lecture-04.md new file mode 100644 index 0000000..6c08a46 --- /dev/null +++ b/conferences/2024/04-class-and-enum/lecture-04.md @@ -0,0 +1,227 @@ +# Conferencia #4 + +## Retomando tipos + +Paradigma de programación: Programación Orientada a Objetos (POO) +- Tipos vs Objetos +- Los **tipos** definen las características que deben cumplir todas las instancias / objetos de ese tipo. +- Los **objetos** representan instancias concretas de tipos, a los que se le asigna un espacio en memoria para almacenar toda la información relevante para su funcionamiento. + +Los lenguajes de programación predefinen un conjunto de tipos básicos (por ejemplo, en C# tenemos `int`, `string`, `bool`). + +¿Podemos crear tipos propios? +> Sí, a partir de componer tipos básicos o complejos. + +¿Por qué querríamos definir tipos nuevos? +- Utilizar con una sintaxis más cómoda para modelar el problema. + > Hablar de los tipos y objetos propios del dominio, y no de tipos básicos. +- Encapsular comportamientos que realizan los objetos del dominio. + > Hablar de "qué" pero ocultar el "cómo". + +C# provee múltiples recursos para definir tipos, entre los que destacan las _clases_, _struct_, _enum_, _delegates_, etc. +En esta clase estudiaremos la sintaxis para definir tipos usando _clases_ y _enum_. + +Vale recordar que una vez que un tipo existe en el programa este puede usarse como tipo de una variable, tipo de retorno de un método o de sus parámetros, posibilitar crear instancias de esos tipos (aunque veremos más adelante que podemos querer crear tipos de los que no se crearán instancias), etc. + +## Clases + +La sintaxis de C# para definir una clase es la siguiente ... + +```csharp +class { + +} +``` + +... donde los `` se utilizarán para definir las propiedades y funcionalidades que debe tener todo objeto del tipo que se está definiendo. + +Algunos `` se pueden definir con la siguiente sintaxis: + +- **Atributos**. Los valores que debe almacenar toda instancia (objeto) de la clase. + + ``` + ; + ``` + ``` + = ; + ``` + + > La visibilidad se puede omitir y por defecto es `private`. + > + > El modificador de acceso se puede omitir, lo cual causa que el atributo sea de instancia. En caso de que se indique como `static` el acceso será a través de la clase. + + Por ejemplo + + ```csharp + class ExampleClass { + int number; + public string textA = "This is a text."; + public static string textB = "This is another text."; + } + ``` + + Luego en otras secciones del programa podemos decir + + ```csharp + ExampleClass example = new ExampleClass(); + Console.WriteLine(example.textA); + Console.WriteLine(ExampleClass.textB); + ``` + +- **Propiedades** para acceder y modificar los valores de las instancias. + + ```csharp + { + get { + ; + } + set { + ; // "value" es visible aquí + } + } + ``` + ```csharp + {get; private set;} + ``` + ```csharp + {get;} + ``` + + > La visibilidad se puede omitir y por defecto es `private`. + > + > El modificador de acceso se puede omitir, lo cual causa que el atributo sea de instancia. En caso de que se indique como `static` el acceso será a través de la clase. + + Por ejemplo + + ```csharp + class Person { + int age; + public string Name {get; private set; } + + public int Age { + get { + return age; + } + private set { + age = value; + } + } + + public int NextAge { + get { + return age + 1; + } + } + } + ``` + + Luego en otras secciones del programa podemos decir + + ```csharp + Person someone = new Person(); + someone.Name = "Juan"; + someone.Age = 30; + Console.WriteLine(someone.Name); // Esto imprime "Juan" + Console.WriteLine(someone.Age); // Esto imprime "30" + Console.WriteLine(someone.NextAge); // Esto imprime "31" + ``` + +- **Métodos** para interactuar con el estado del objeto o para cambiarlo. + + ``` + ( ) { + ; + } + ``` + + > La visibilidad se puede omitir y por defecto es `private`. + > + > El modificador de acceso se puede omitir, lo cual causa que el atributo sea de instancia. En caso de que se indique como `static` el acceso será a través de la clase. + + Por ejemplo + + ```csharp + class Person { + string name = "Juan"; + public void SayHello() { + Console.WriteLine($"Hola, me llamo {name}"); + } + } + + class MyTools { + public static int Successor(int number) { + return number + 1; + } + } + ``` + + Luego en otras secciones del programa podemos decir + + ```csharp + Person someone = new Person(); + someone.SayHello(); // esto imprime "Juan" + + int number = MyTools.Successor(5); + Console.WriteLine(number); // esto imprime "6" + ``` + +- **Constructor**. Un tipo especial de método, encargado de especificar cómo construir instancias de la clase. + + ``` + ( ) { + ; + } + ``` + + Por ejemplo + + ```csharp + class Person { + string name; + public int Age {get; private set; } + + public Person(string name, int age) { + this.name = name; + Age = age; + } + + public void SayHello() { + Console.WriteLine($"Hola, me llamo {name}"); + } + } + ``` + + > Si hay conflicto de nombre entre los parámetros y los cambos, se usa `this.` para desambiguar. Si no se incluye `this.` entonces se asume que se está refiriendo al parámetro o variable local en caso de conflicto. + + Luego en otras secciones del programa podemos decir + + ```csharp + Person someone = new Person("Pablo", 30); + someone.SayHello(); // esto imprime "Juan" + Console.WriteLine(someone.Age) // esto imprime "30" + ``` + +## Enum + +Permite definir un tipo que consiste en una asignación semántica a los números enteros. Sirve para definir tipos que tienen valores fijos conocidos en tiempo de compilación. + +La sintaxis de C# para definir un enum es la siguiente. + +```csharp +enum { + +} +``` + +Por ejemplo + +```csharp +enum Result { + Win, + Lose, + Tie +} +``` + +Luego en otras secciones del programa podemos usar `Result` como cualquier tipo y para hablar de sus valores usamos `Result.Win`, `Result.Lose` y `Result.Tie`. +